AN INTEGRATED DEVELOPMENT PLATFORM FOR DISTRIBUTED PUBLISHING AND MANAGEMENT OF HYPERMEDIA OVER WIDE AREA NETWORKS

Abstract: The present invention addresses the critical needs of publishers seeking to create and publish hypermedia content in electronic form across wide area networks ("WAN's") such as the World Wide Web. Toward this end, a client-server development platform is provided for handling the important functions of document authoring, content-based indexing and retrieval of documents, management and control of proprietary assets, and support for developing form-driven interactive services, all in a manner that is uniquely and seamlessly WAN-integrated.

Description: AN INTEGRATED DEVELOPMENT PLATFORM FOR DISTRIBUTED PUBLISHING AND MANAGEMENT OF HYPERMEDIA OVER WIDE AREA NETWORKS HELD OF THE INVENTION The present invention relates to the field of authoring, publishing, and managing electronic hypermedia documents across distributed, wide area networks such as the World Wide Web. BACKGROUND OF THE INVENTION The distribution of information is being revolutionized before our very eyes. Wide area networks ("WAN's"), notably the Internet, are assuming the role of "information superhighways" and are distributing electronic embodiments of mail, textbooks, magazines, advertisements, and even audio and video clips around the world. Herein, the term "document" denotes and includes any and all such electronic content, generically. Figure 1 conceptually illustrates the basic architecture of a "client-server" WAN like the Internet. Servers lOa-n form the backbone of the WAN. The servers are interconnected by a telecommunications infrastructure and exchange information in the form of one or more recognized protocols, such as protocol 30. For example, in the case of the Internet, network protocols include FTP, for file transfer, and Telnet, for remote log-in. Each server effectively represents and services its one or more "clients." Basically, the clients are the ultimate sources and targets of underlying information, while the servers dispatch and receive messages across the WAN in compliance with network protocols. Each client may correspond to a single user's computer, or may itself be hierarchically complex and may comprise a further sub-network or collection of numerous computers, such as the well- known, proprietary sub-networks of America Online, CompuServe, and Prodigy. In this way, information of any kind can be distributed worldwide in electronic form at telecommunications speeds. One of the most rapidly expanding aspects of the Internet is the World Wide Web (the "Web"). The Web is comprised of those Internet servers (and their clients) able to support the Hyper-Text Transfer Protocol, better known as "http." The Web allows documents and graphical materials to be interlinked by means of "hypertext" (or more generally, hypermedia) document elements. When a user utilizes a cursor control device to select and "click" on a hypermedia item in one document, a related document will automatically be accessed as identified by that link. For example, Figure 2 illustrates a simple example of a popular Web document known as a "home page." Home page 40 includes title 42, graphic image 44, instructional text 48, and list of bullet items 46a-c. Selections 46a-c are each hypertext. A Web hypermedia item is actually encoded with a Uniform Resource Locator ("URL") tag, which literally addresses a document located on a remote network server. If a client of a Web server is equipped with suitable "browser" software, then a user of that client can point and click on any one of the hypermedia items within home page 40, and an http request to view the associated, linked content residing elsewhere on the Internet will automatically be generated and dispatched by the client's server to the appropriate Internet server which "hosts" the linked document. The linked material will then automatically be retrieved and ultimately displayed on the client. Http further includes the Hyper-Text Markup Language ("html"), which may be used to specify a certain layout structure for Web documents, e.g., specifying subsections of the document as a title, image, list, etc. Html specifications are interpreted by a client's browser, resulting in an appropriate display on the particular client's computer platform. A survey and discussion of many popular Web browsers is provided in the February 7, 1995, issue of PC Magazine ("PC Magazine" .. at pages 173-196. An important challenge that must be addressed, especially in light of the burgeoning expansion and popularity of the Internet and the Web, is how best to facilitate the authoring and publishing of hypermedia documents on the Web. Many large and small publishers of content — such as newspaper and magazine publishers, for example — wish to make their content available in on-line form to subscribers. However, this opportunity presents a major bottleneck, because high-quality development platforms and authoring tools have not yet been developed that adequately facilitate the authoring and publishing of hypermedia on a distributed WAN like the Web. A summary of the primary limitations of current Internet and Web publishing tools follows: 1. Current publishing tools are typically not fully network-integrated. Browsers or other "cruiseware" help users view existing WAN content, but do not generally support authoring of new WAN content. Current authoring tools, on the other hand, are typically either "stand-alone" local products, or at best offer a limited bridge to WAN access such that authoring and WAN navigation remain fundamentally non-integrated processes. For example, in order to publish a document on a WAN, it is typically necessary to edit documents in a local storage context using authoring tools, and thereafter manually copy the documents to a WAN server. Manual copying is often tedious and inconvenient, especially where a publisher frequently publishes a large quantity of content from diverse sources, including text files, graphics images, video and sound clips, etc. Yet, current authoring tools generally provide little assistance with this chore. The non-integrated nature of current authoring tools presents other difficulties and limitations as well. For example, it is not generally possible to "open" multiple WAN documents for editing and to transfer text, images, and URL's among those documents in the seamless fashion as is presently done with typical word processors for local computer documents. As another example, current Web authoring tools generally do not provide full WYSIWYG ("What You See Is What You Get") feedback as to html markups and hypermedia links. In other words, the creation and editing of documents is typically performed in a purely local context; html and URL codes must then be separately tested in a serial fashion, by loading the document into a WAN browser or the like. This serial, iterative process is highly inefficient. 2. Current WAN publishing tools provide little assistance with managing collections of documents. Although the World Wide Web is famous for supporting hypermedia document links, current tools provide scant support for maintaining and operating on collections of related documents as a group. Much progress is needed in this area. For example, an integrated publishing environment should preferably allow users to visually navigate through collections of interconnected documents; to upload, download, and transport collections of documents from one WAN location to another as a group; and to set access privileges or other attributes for a WAN collection as a group. Current tools generally fall far short of these objectives. 3. Current publishing tools provide little assistance with content-based indexing and retrieval. Current navigational tools, such as browsers, provide very little assistance with systematically organizing and searching the information content contained within the numerous sites comprising a network like the Internet. Clearly, as the volume of both information and traffic on the Internet continues to explode, publishers need to be able to make their content available to subscribers in an intelligently organized fashion that facilitates uniform, content-driven search and access. 4. Current publishing tools provide little assistance with asset management. For commercial publishers of proprietary material like newspapers or periodicals, asset management is critical. In other words, publishers need to be able to control and limit access to their WAN documents, and to keep track of usage for billing and other purposes. Yet, currently available tools for WAN publishing generally ignore this area almost completely. 5. Current publishing tools do not address the creation of application programs. For on-line network publishing to realize its full potential, publishers will want to do more than simply dump passive, one-way content onto the Internet. They will want to provide application programs allowing network users to take advantage of interactive on-line services such as subscribing to a publication, registering for a conference, or perhaps even more exotic applications like participating in multi-player games contests. Current network publishing and authoring tools largely ignore this area. Accordingly, there is a great need for a new development platform for distributed publishing that overcomes the various limitations described above. This need is especially pronounced and important in view of the rapid expansion of interest in die Internet and the Web, and the tremendous economic opportunities presently available to publishers if a suitable development platform can be provided. Recently, authoring tools have begun to emerge, which attack some of the foregoing problems in piecemeal fashion. See PC . Magazine at pp. 110-196. However, there remains a great need for a comprehensive solution to the problems described, and especially for an authoring/publishing tool that is truly and fully network-integrated. SUMMARY OF THE INVENTION We disclose herein a development platform technology for publishing hypermedia documents across wide area networks ("WAN's"). This technology supports key publishing functions including document authoring, management and publishing of document collections, and support for database operations and interactive application program development. These functions are supported in a uniquely and fully WAN-integrated manner, as described further below. In one feature of the present invention, a WAN document residing on a WAN server may be accessed via a hypermedia link, edited, and stored to the same server or any other WAN server, using a client computer coupled to the same server or any other WAN server. The processes of accessing, editing, and storing may be performed using a seamless user interface on the client computer. By "seamless" user interface we mean that users are not required to request additional steps such as intermediate copying or storage of the document being edited, or to switch back and forth among distinct "modes" or interfaces. Thus, browsing and editing of WAN documents is truly integrated. A related feature of the invention allows convenient transfers of content and/or hypermedia links among a plurality of WAN documents, such as by "cut and paste" or "drag and drop" copying. Another related feature provides immediate execution and feedback for any display instructions added to the document using a standard WAN mark-up language. In another feature of the present invention, at least two WAN documents residing on the same or different WAN servers are accessed, and a hypermedia link addressing one of the documents is inserted into another. Once again, the processes of accessing and editing are performed using a seamless user interface on a client computer. In a related feature of the invention, a list of suggested target hypermedia links is automatically generated using statistical language processing techniques, and the link to be inserted is interactively chosen from that list. Another feature of the present invention provides a method for publishing and managing a collection of related documents on a WAN. The related documents to be included in the collection are specified, and a desired operation (such as setting access controls or changing location) may then be performed collectively on each document in die collection, simply by interactively issuing a single command corresponding to the operation. A related feature includes hypermedia links between documents of the collection, which address target documents relatively to source documents; i.e., each link address does not specify an absolute address for the target independently of the source. In another related feature, elements of the collection including documents and hypermedia links are graphically depicted using icons and connecting lines, thereby facilitating convenient, visual navigation and organization of the collection. In a further feature, the present invention includes a method for providing form- driven interactive services on a WAN. A form-driven service is developed by creating a template form comprising one or more informational fields, as well as one or more hypermedia links addressing a database system or otiier utility program stored on an application server. The form-driven service is utilized by filling in the informational fields, and "clicking" or otherwise signalling on the hypermedia link when ready. In response, the application server is sent an appropriate WAN message, and processes die form. These steps (except the last step) are performed using a seamless user interface environment, so there is once again no need for users to switch interfaces or request any intermediate copying in order to perform the process of creating and filling in a template form and signalling when the form is ready for processing. BRIEF DESCRIPTION OF THE DRAWINGS Figure 1 illustrates a basic, high-level architecture for a typical client-server WAN such as the Internet or the World Wide Web. Figure 2 illustrates a simple example of a typical "home page" document on the World Wide Web. Figure 3 broadly outlines a client-server architecture in accordance with the present invention. Figure 4 illustrates a preferred document editor environment in accordance with the present invention. Figure 5a illustrates a flow diagram for a scenario in which WAN hypermedia documents are created and edited in accordance with the present invention. Figure 5a illustrates a flow diagram for a second scenario in which WAN hypermedia documents are created and edited in accordance witii the present invention. Figure 6 illustrates a preferred set of interactive commands for working with a collection of interrelated hypermedia documents. Figure 7 illustrates a preferred graphical interface for organizing and working widi a collection of interrelated hypermedia documents. Figure 8a is a screen image illustrating use of the preferred "NaviLinks" facility to generate suggested hypermedia links. Figure 8b is a screen image further illustrating use of the preferred "NaviLinks" facility to generate suggested hypermedia links. Figure 9 illustrates a flow diagram for developing and running WAN-based, form- driven, interactive application programs in accordance with the present invention. Figure 10a illustrates a preferred interface form for adding a customer feedback table to an indexed database, in accordance with the present invention. Figure 10b illustrates a default template form for adding a particular customer's feedback to an indexed database, in accordance with d e present invention. Figure 10c illustrates a modified template form for adding a particular customer's feedback to an indexed database, in accordance with die present invention. Figure lOd illustrates a template form for searching an indexed database for particular customer feedback, in accordance widi the present invention. DETAILED DESCRIPTION OF THE INVENTION Introduction Figure 3 provides a broad outline of a client-server architecture in accordance wid the present invention, for use in the context of a WAN such as illustrated in Figure 1. User's client machine 20d preferably includes digital computer facilities including CPU 68, user I/O peripherals 66, and storage device 64 (including internal and external memory) storing operating system 62 and client software 60. WAN server lOd, preferably coupled to client 20d ti rough a high-speed local connection, is equipped with digital computer facilities analogous to those of client 20d, and also with server software 50. As described in much greater detail below, client software 60 and server software 50 preferably share the responsibility for providing advantageous and innovative electronic publishing capabilities in accordance with the present invention. Note that a user of client computer 20d seeking the benefits of the present invention need only have client software 60 available on client computer 20d, and all or part of server software 50 available on server lOd (depending on die particular features desired). The user can then advantageously access and publish documents to and from the remainder of die WAN in accordance with the present invention, even though otiier computer systems on the WAN have not been similarly modified or upgraded. The inventors are, as of this writing, in the process of developing a preferred embodiment of die present invention including client software 60 called "NaviPress" and server software 50 called "NaviServer." As a supplement to the detailed description provided below, an Appendix is provided herewith which contains illustrative source code, architectural specifications entided "NaviPress and NaviServer: A Client-Server Publishing System for the World-Wide Web" (hereinafter "White Paper"), and excerpts from a draft User Manual for NaviPress and NaviServer. The reader is referred to die Appendix for more details regarding tiiis preferred embodiment, and the Appendix materials are incorporated herein in their entirety by this reference. Network-Integrated Editing The present invention enables users to access, edit, and store documents distributed throughout a WAN, in the advantageous manner of state-of-the-art, private computer or local area network word processing tools. In accordance with the present invention, the basic process framework by which WAN documents are accessed, edited, and stored is seamless and is substantially the same as if all steps occurred locally on a private computer. In particular, users are not required to perform any intermediary downloading or copying steps, or to switch back and forth among distinct "modes" or interfaces in order to access and browse WAN documents, to edit diem, and to store diem. As a more concrete illustration of this capability, Figure 4 illustrates a preferred, menu-driven document editor in accordance with die present invention. Typically, menu bar 70 would be displayed continually at die top of a computer display "window" in which a particular document is being edited. "Pull-down" menus, such as "file" menu 72, are displayed when a user selects a corresponding item from command bar 70, preferably using a cursor control device. For example, file menu 72 includes commands to "open" existing documents for editing, and to "save" such documents as revised, etc. This general, menu- driven metiiodology is of course by now familiar to those of ordinary skill in die relevant arts. The present invention enables these capabilities to be applied seamlessly across a wide area network. In otiier words, a user can conveniently access, edit, and save any WAN document in much the same way as the user has been accustomed to doing with respect to documents residing locally on the user's private, personal computer. Consider a scenario in which multiple WAN hypermedia documents are being worked upon. As indicated in Figure 4, edit menu 74 includes "cut and paste" commands allowing text and other information to be transferred conveniently between multiple WAN documents. "Cut" and "copy" commands will typically post to a "clipboard" (i.e., temporary storage) selected content from any document being edited, while the "paste" command will insert whatever content is currently held in the clipboard into a different document at a point of insertion selected by the user. The present invention provides further advantages in die context of hypermedia WAN documents, as illustrated by the scenarios described in the flow charts of Figures 5a and 5b. With respect to Figure 5a, at step 80 the user of client computer 20d invokes file menu 72 to access a source document, such as by "opening" an existing document located on any WAN server. In this example, the source document contains a hypermedia link addressing a target document, located on the same or any other WAN server. At step 82, the user accesses the target document by "clicking" on die hypermedia link using a cursor control device, which immediately opens the target document for editing in accordance with menu bar 70, preferably in a separate document window. At step 84, the user can immediately edit and revise the accessed target document. This step preferably includes use of a markup language recognized on the WAN, such as html; elements menu 76 and format menu 77 in Figure 4 provide convenient tools for creating and editing html content with immediate WYSIWYG feedback. The editing step also preferably includes interactively transferring or copying any selected portion of the source document to die target document (or vice versa), such as by "cutting and pasting" or by "dragging and dropping" the selected portion using a cursor control device. Moreover, the copied portion may include hypermedia links (URL's) or other mark-up codes, and any such mark-up codes will immediately be active as soon as inserted into die target document. Because the browsing and editing environment is seamless in accordance with the present invention, these editing tasks can now be performed witiiout requiring users to switch between separate interface modes or to temporarily download documents into local storage, as was traditionally necessary. Finally, at step 86, die target document is saved as revised to any WAN server by using die "save" or "save as" commands of file menu 72. Note that server lOd, die source server, target server, and die ultimate destination server of the target document may all be the same server, or may all be different. In die scenario described in Figure 5b, at steps 90 and 92 die user of client computer 20d accesses a source document and a target document, such as by invoking file menu 72. The source and target may originally be located on any wan servers. At step 94, the "copy URL" command of edit menu 74 is used to post a hypermedia pointer addressing die target document onto a clipboard for temporary storage. (Recall that "URL" is the term for a hypermedia link on die World Wide Web, as discussed earlier in die Background section.) At step 96, die "paste URL" command of edit menu 74 is used to paste the stored hypermedia link onto a selected "anchor" item of content within the source document. At step 98, this new document, including the new hypermedia link, may be "published" by storing it to any WAN server, simply by using die "save" commands of file menu 72. Thus, in accordance widi die present invention, publishing hypermedia content across a WAN is achieved in a highly advantageous manner that fully and seamlessly integrates hypermedia browsing and editing. As briefly noted above, die WAN-integrated editing environment is enhanced by elements menu 76 and format menu 77 which provide WYSIWYG feedback for html markup authoring without any need for users to separately launch a browser program or upload the document being edited. Other, preferred features of the editing environment depicted in Figure 4 include WAN browser menu 78, display options and preferences, and access to help. Menu bar 70 further provides access to various WAN tools and services discussed further below, including "NaviLinks" link generation, form-driven database update and search, and asset administration services. In summary, prior art technology has traditionally separated between WAN "browsing" on one hand, in which WAN documents are accessed and mark-up codes are inteφreted and executed, and document editing on the other hand, in which documents are modified. Conventionally, users must manually switch between distinct browsing and editing environments or "modes," and/or perform intermediate steps in which WAN documents of interest are downloaded to die user's private local storage, thereafter edited, and tiiereafter uploaded back to die WAN. The present invention now enables users to access WAN documents, copy content (including hypermedia links and other mark-up codes) among multiple WAN documents, and execute WAN mark-up codes, all in a seamless fashion without requiring intermediate steps. Moreover, these capabilities require only the user's computer system to include software implementing die browsing and editing environment, and do not require any modification of otiier WAN computers. For more details on an exemplary embodiment of die WAN document editing and browsing environment, the user is referred to the Appendix, and especially to the draft User Manual at Chapters 2, 3, and Appendix A. Exemplary source code for use in implementing this unique environment is also included in the Appendix. Working Widi Collections of WAN Documents Anodier aspect of the present invention is the ability to publish, maintain, and otherwise operate on collections of multiple, related documents as a group. This is an especially valuable capability in the context of hypermedia collections, where tiiere are explicit links between specific, related portions of documents. Figure 6 illustrates a preferred, menu-driven autiioring environment called "the MiniWeb" for working with collections of related documents in accordance with die present invention. Typically, menu bar 100 is displayed continually at the top of a computer display "window" in which a particular collection is being operated on. Many of the basic operations provided by the pull-down menus available through menu bar 100 are performed collectively upon the current document collection (or "miniweb"); in other words, a single command will be applied to all members of the collection, as a group. For example, pull- down "file" menu 102 includes commands to "save" a miniweb to any specified location in the WAN. When invoked, the command automatically stores all documents and objects in the collection to the desired new (or old) storage site. Preferably, edit menu 104 includes commands to globally search and replace a common portion of content, such as an updated company logo or URL, shared by many or all documents in the collection, although this particular command option is not explicitly shown in Figure 6. Similarly, tools menu 106 performs administrative tasks, such as setting access controls (i.e., costs and security privileges), for collections as a group. A related aspect of this invention involves the ability to transport collections of documents interrelated by hypermedia links in a convenient manner. Those of skill in the art recognize that when the target reference of a hypermedia link is moved, the link is thereby "broken," much like die address on a letter to a recipient who has moved and left no forwarding address. Thus, moving a collection of documents interrelated by numerous hypermedia links has been extremely onerous using prior art technology, since die hypermedia links must manually be "fixed" to address new locations. In accordance with the present invention, one or more relative hypermedia links are preferably created among the documents of a collection. A "relative" link only addresses its target document relative to the source document's address. In other words, only a portion of die full target address is given, namely, a portion sufficient to locate the target relative to the source. Preferably, a specification of a hierarchical directory structure for each collection is maintained in a separate file along with the collection, so that only the topmost page in the collection need be tied to an absolute address, while other hypermedia links witiiin the collection can be made relative and still be interpreted properly. Sample listings for such a specification are included on die following pages. Because the links are relative, they do not need to be modified when d e collection is moved. r.avidoc 1.0 graph * 1 nametype«0 title * style= templates Pages: "top.htm" Ups" Styles-* Titles'The NaviServer Documentation" 1 94 467 "install.htm* Ups" Style="" Title "installing the NaviServer" 1 "s t artup.htm" Ups"" Styles- • Title "Starting U p the NaviServer' 1 "security.htm' Up * *" Styles" Titles"Security on the NaviServer" 1 "costs.htm" Up«" Styles" Titles'Charging money for access * 1 "search.htm" Ups" Styles" Title 'Searching the NaviServer" 1 "srchdata.htm" Up * " Style-" Titles"Searching Database Tables" 1 "srchpage.htm" Ups' ' Styles" Title * 'Searching for Pages' 1 -hitlist.htm* Ups"" Styles" Title "Hitlists and Hittables" 1 "hilite.htm" Up * ' Styles" Titles'Hiliting and MoreLikeThis" 1 ■ under.htm" Up*' Styles" Titles-Coming Soon!' 1 "entup.htm" Ups" Style*" Titles*Entering Data and Updating It* 1 "smartlnk.htm' Ups" styles " Title*'SmartLinking' 1 "describe.htm" Ups-- Styl " Title * -Describing Pages' 1 "custom.htm- Ups" Style*' Titles'Customizing Entry, Update and Search Forms" 1 "archive.htm* Ups" Styles " Title * "Archive Ver-sioning' 1 "logging.htm' Ups-- Styles- " Titles-Logging' l "ops.htm' Up** Style * Titles-NaviServer URL Reference" 1 "maktable.htm' Up Style * ' Title**Creating.and Dropping Tables* 1 ■ tables.htm' Up»" Style Title * 'NaviServer System Tables" 1 ■ page21.htm' Up«" Style Title * "Please title this page. (Page 21 in servdocs) "sumobanr.gif* Up * Style * ' Title*' "sumoguyl.gif Up- Style * ' Title * ' "sumoguy2.gif" Up * Style* ' Title * ' "sumoguy3.gif" Up * Style * ' Title*' "sumoguy .gif* Up* Style* ' Title * " "sumoguy5.gif* Up* Style* " Title * - "sumoguy6.gif* Ups" Style" • Title * - "sumochar.gif Ups" Style" ' Title * ' "sumoleaf.gif Ups" style* " Title * " "sumoguy7.gif* Up * " Style* " Title * - "sumoguy8.gif Ups" Style* " Title * - "fu ibrch.gif* Up * ** Style* • Title * ' "fujimt.gif Up * " Style*" Title * " 1 'sumobboo.gif* Up*" 1 Style * " Title * • sumofeet.gif" Up«" Style * " Title * 'sumohnds.gif Up * Style* •• Title * "sumoarm.gif* Up»"* Style * ' ■ Title * " 1 "cthulhu.gif" Up»" Styl*"* ■ Title*" 1 "iceman.gif" Up*" Style*" Title*" 1 "sumochr2.gif Up-*' Style* " Title * " l Ghosts: "srchdata.htm* θ "http://www.navisoft.com/STUB" 2 'sus_oguy5.gif* "srchpage.htm" 2 "sumoguy€.gi " 8 'http://www.navisoft.caai/STUB' 0 '/NS/GetSβarchFoπn/n«_dβfault_collection* "hitlist.htm* 0 '/NS/GetSearchForm ns_default_collection- 0 -http://www.navisoft.com/STUB- 0 'http://www.ncaa.uiuc.edu/SIXi/Software/XMosaic/help-on-version-2.5b5.html 0 'http://www.netseape.com/info/newsreleasel .html* 0 'http://www.w3.org/hypertext/WWW/Arena/* 0 "/NS/GetSeaxchForm/ns_total_chargβs ■ 2 "sumochar.gif "hilite.htm" 0 '/NS/MorβLikeThis/?Urls%2fsβrvdoc%2ftop.htm* 0 * /servdoc/top.htm* 0 "/NS/GetLHP/?Urls%2fservdoc%2ftop.htm_&terms*cool" 2 "sumoleaf.gif" "under.htm" 2 "cthulhu.gif" "entup.htm" 8 "http: //www.navisoft .com/STUB" 2 " sumoguy7. gif 0 " /NS/GetEntryForm/ns_permissions " "Smartlnk .htm- 2 " fuj ibrch . gif " " describe . htm* 8 'http : / /www.navisoft . com/STUB" 2 ' fujiat .gif " custom. htm" 2 " sumofeet . gif " 1 " /N5/G«tSearchForm/ns.columns" "archive.htm* 4 "startup.htm* 2 "sumohnds.gif" 0 "http://navisoft.com:8001/NS/ArchiveVersions/index.html" 0 "http://navisoft.com:8001/index.html" 0 "http://navisoft.com:8001/NS/Archive/19950222000000/index.html' "logging.htm" 4 "startup.htm* 2 "sumoarm.gif "ops.htm* 2 'iceman.gif * 1 "/NS/GetSearchFormPicker" 1 "/NS/Admin" 1 "/NS/About" 1 '/NS/GetNewTableForm" "maktable.htm' 0 "/NS/GetDropTableForm" 0 "/NS/GetCrβateTableFor * 2 "su obboo.gif" "tables.htm* 2 'sumoch 2.gif" ■ page21.htm" "sumobanr.gif" "sumoguyl.gif* 'sumoguy2.gif "sumoguy3.gif" "sumoguy .gif" "sumoguy5.gif" ■ sua_oguy6.gif "sumochar.gif* "sumoleaf.gif "sumoguy7.gif" ■ sumoguyβ.gif" "fujibrch.gif" "fujimt.gif" "sumobboo.gif" "sumofeet.gif" "sumohnds.gif" "sumoarm.gif" "cthulhu.gif" "iceman.gif" "sumochr2.gif A preferred embodiment of die MiniWeb facility that has been described includes an advantageous, graphical front-end for viewing and navigating witiiin a collection of hypermedia documents. Figure 7 illustrates an example of such a miniweb interface. Display icons HOa-n each represent corresponding documents located anywhere on the WAN, or anywhere within the user's local storage. Arrow icons 112a-n indicate hypermedia links between documents, in die direction indicated by the arrows. Thus, the miniweb display provides an intuitive, graphical view of the relationship among a collection of hypermedia documents. The graphical interface of Figure 7 is preferably displayed in a separate window of client computer 20d, alongside document editing windows in accordance widi Figure 4. Users can preferably use die miniweb window as a short-cut to access desired documents witiiin a collection by simply "double-clicking" on the corresponding icon in die miniweb, or by "dragging and dropping" an icon from the miniweb onto a document editing window. Moreover, the precise appearance of icons and connecting arrows preferably indicates die nature or state of the corresponding document or link. For example, icon 1 lOi represents a sound file, while icon 110b is a hypermedia "web" document, as suggested by die appearance of those two icons. Further, the color and shading of icons and arrows may indicate such states as a modified and unsaved document, or a relative or absolute address link. For more details regarding the graphical interface of Figure 7 and its preferred uses, the reader is referred to the draft User Manual in the Appendix, and particularly chapters 4 Appendix B thereto. Once again, source code included in the Appendix provides exemplary means for implementing the miniweb facility we have described. Automated Authoring of WAN Hypermedia: "NaviLinks" Most content on the World Wide Web is not originally created as hypermedia. For example, news articles, product brochures, and other literature originally created for non- interactive environments do not initially contain any hypermedia links to other documents. Such links must be creatively defined and implemented. A preferred feature of the present invention provides assistance in the authoring of hypermedia WAN documents, by facilitating and partially automating the creation of useful hypermedia links. This facility, which we call "NaviLinks" herein, uses statistical language processing algorithms to generate automatically a list of suggested, possible hypermedia links between a source document and a collection of potential target documents. A human author can then review the suggestions in a convenient manner, and choose to incorporate, modify, or discard them. The NaviLinks facility is preferably integrated along with the publishing tools described above, and as illustrated in die "screen shots" of Figures 8a and 8b. Botii figures depict document editing window 120, including menu bar 70 in accordance with the teachings of Figure 4 and the earlier discussion herein. A document entitled "Wild Rice Risotto" (evidently a recipe) is currently open witiiin window 120. In the example shown, the user has already invoked the NaviLinks facility for assistance in creating hypermedia links from the recipe document to related documents. NaviLinks window 124 is thus shown overlapping on document editing window 120. Window 124 displays list 126 of suggested anchor items. An "anchor" item is an item of content within a source document encoded as a hypermedia link; users "click" on anchor items to bring up linked target documents. Thus, the highlighted entry in list 126 corresponds to item 122 in the recipe document, namely, the recipe author's name (Carey Schnell-Wright). NaviLinks window 124 also displays list 128 of potential target documents for the currently highlighted anchor item. The lists of suggested anchor items and potential targets are generated automatically, preferably using statistical language processing techniques such as provided in the Xerox Lexical Technology ("XLT") package commercially available from the Xerox Corporation. Because of the integrated nature of the tools described herein in accordance with the present invention, the process of exploring and selecting among the suggested anchor items and corresponding hypermedia links shown in Figure 8a can be performed very conveniently. For each anchor item in list 126, a suggested link in list 128 can be encoded directly onto the anchor item in the source document by pressing "Apply" button 132; or, the target document addressed by die suggested link can itself be accessed and edited in yet anotiier editing window, by pressing "Show Page" button 130. Figure 8b illustrates the results of pressing these buttons. The visual appearance of anchor item 122 is updated to indicate that it is now encoded as an URL (i.e., a hypermedia link), as a result of the user "applying" a suggested link. In addition, as a result of the user selecting a "Show Page" request, document editing window 134 has been created overlapping on windows 120 and 124, and displays an open WAN document containing anotiier recipe by the same author and entitled "Marjoram Potato Casserole." WAN-Integrated. Form-Driven. Interactive Services A hypermedia publishing platform should preferably support not only the authoring and distribution content, but also a variety of form-driven interactive services, such as content-based indexing of documents, and controlled access to proprietary WAN documents. Preferably, application developers and end-users should be able to generate and store new forms, retrieve existing forms, fill out forms, and submit them for appropriate processing, all in a convenient and seamless manner utilizing an integrated editing and browsing environment such as described earlier in connection with Figures 4-7. A great many, desirable, interactive WAN services are database-oriented. For example, a service might involve a particular database "view" (i.e., a specified set of indices) for indexing WAN documents, for managing historical versions of WAN documents, for collecting and reviewing customer feedback, or for relating specified access controls (such as security restrictions and access costs, perhaps of a hierarchical nature) to specific, proprietary WAN documents. Therefore, the form-driven interface environment of the present invention is preferably integrated not only with editing and browsing tools as previously described, but also with a database management system such as die Ulustra object relational database management system. Figure 9 illustrates a sample process flow diagram for developing and utilizing form- driven, interactive, database services in accordance with the present invention. At step 140, a developer user begins the process of setting up a new interactive service by using client computer 20d to create a new database table tor the service, preferably using an integrated authoring environment such as window 160 in Figure 10a. As shown, window 160 includes menu bar 70, and die seamless browsing and editing facilities described earlier herein. The table created in step 140 will include a plurality of data fields 162a-n. As illustrated in Figure 10a, each one of data fields 162a-n preferably may be associated with various specifications such as a required data type, and whether or not database entries in the table will be indexed (and hence searchable) using that field. As indicated by comment 164 in Figure 10a, step 140 is completed by pressing a "create table" button or the like. The "create table" button is actually just a special kind of hypermedia link which transmits a requested operation for processing by a target WAN server on which server software 50 is available, as will be described in greater detail further below. In this case, clicking on a "create table" button sends a network message formally registering the new database table with server lOd or another selected WAN server (hereinafter, the "application server") on which server software 50 including a database management system is available. Once a database table is created, at step 142 template forms are generated for interactively updating and searching the database described by the new table. Updating, such as by adding a new database entry, may interactively be performed using a form as illustrated in Figure 10b, in which informational fields 166a-n correspond to the data fields 162a-n specified in die database table. Thus, a user who accesses the entry form at step 144 can then describe the database attribute values for a new entry at step 146 simply by filling in informational fields 166a-n. Analogous comments apply with regard to forms for submitting a specific database search or query, such as the form of Figure lOd which includes corresponding information fields 174a-n. Because description and search forms are integrated with the authoring environment previously described, as indicated by die presence of menu bar 70 in Figures 10b, 10c, and lOd, users can seamlessly take full advantage of the editing capabilities of that environment in the course of filling out description or search forms. For example, while a WAN document is being accessed and edited by die user in one display window, the user can fill out a corresponding description form or access control form in another window, concurrently. Moreover, users can even modify and customize the style and appearance of entry or search forms, by using the editing facilities of menu bar 70, such as the html mark¬ up commands of the Elements and Format menus (as discussed previously in connection with Figure 4). For example, Figure 10c depicts an edited version of Figure 10b that still corresponds to the database table of Figure 10a. Thus, fields 170a-n of Figure 10c map directly onto fields 166a-n of Figure 10b, but are merely displayed in a somewhat different appearance. Thus, the steps of generating and filling in new tables, entry forms, and search forms are seamlessly integrated with the editing and browsing environment previously described. Moreover, even the step of submitting a completed form to the application server for processing may likewise be performed in seamless fashion together with the preceding steps. Thus, at step 148, a user who has completed a database entry or search form submits the form to the application server by pressing a hypermedia "enter" button or the like using a cursor control device as indicated by comments 168 (on Figure 10a) and 172 (on Figure 10b), akin to the "create table" button described above in connection with Figure 10a. Entry and search forms are thus "live," meaning that completing a form and interactively signalling a hypermedia link included in die form will automatically send an appropriate message to the application server, causing server software 50 to initiate appropriate database actions at step 150. The user need not invoke a separate interface, copy any files, or compose any database scripts. Thus, to enjoy interactive database services, users can simply fill out forms using the same environment they use to access and edit documents. Note that a WAN document referenced in a database may preferably be located anywhere in the WAN in accordance with the present invention, and need not be local to the application server. From the standpoint of server software 50 the database tables reference and index WAN-compatible URL's, (i.e., WAN address pointers), and so need not store documents locally. Note also that, multiple tables and hence multiple indexing views and forms covering the same documents are possible. For example, an administrator might systematically index all documents on a server, while individual users might create their own indexing schemes for documents and criteria of special interest. For more details regarding various menu-driven interactive services provided by a preferred embodiment of die present invention, the reader is referred to die Appendix, and especially to chapter 5 of the draft User Manual and chapter 3.3 of the White Paper. Details regarding a preferred architecture and implementation for server software 50 in support of menu-driven interactive database services will now be described. Preferred embodiments of client software 60 ("NaviPress") and server software 50 ("NaviServer") communicate through a WAN hypermedia protocol such as http. All requests and responses between client and server are accomplished tiirough http. Thus, NaviPress sends requests to NaviServer using GET, PUT, POST, BROWSE, and DELETE methods, and NaviServer returns results using standard http return codes, as well as some special content types in accordance widi the present invention. Both NaviPress and NaviServer are thus "open" in the sense that any http-compliant client computer can access most services provided by NaviServer, and NaviPress can be used with any http-compliant WAN server. NaviPress requests for services from NaviServer may contain ordinary URL's, but sometimes contain special URL's that map to server functions. If a request is not immediately serviceable — e.g., GET a page for browsing — NaviServer checks to see if the URL contains a special data field encoding a registered operation that maps to server-specific processing code. For example, NaviServer preferably includes about twenty pre-installed operations, listed in Table 1, for implementing common server functions such as publishing, administration, information retrieval, and document management functions. These special URL's take die general form of "/prefix/operation/arguments," where the "arguments" are an arbitrarily long string that is passed to the "operation." The NaviServer looks for registered prefixes and recognized operations, and then passes the request to the appropriate utility program or process. NaviServer is designed so tiiat custom services can be added easily. Application developers can register new operations with their own unique prefixes. Since a standard, open protocol is used for communications between client and server, even vendors of other authoring tools can write interfaces that advantageously publish content to a server running NaviServer software. Table 1. Examples of NaviServer operations For more details on this subject, the reader is referred to the Appendix hereto, especially the White Paper at chapter 4, and sample source code for the server software and related code. Other Variations The fully integrated client-server environment illustrated herein represents a very powerful and flexible platform for authoring hypermedia content. Detailed illustrations have been provided for the edification of those of ordinary skill in the art, and not as any kind of limitation on the scope of the invention. Numerous variations and modifications within the spirit of the present invention will of course occur to those of ordinary skill in the art in view of the preferred embodiments that have now been disclosed. Such variations, as well as any otiier systems embodying any of die following claims, all remain within the scope of the present invention: APPENDIX TO PATENT APPLICATION FOR "AN INTEGRATED DEVELOPMENT PLATFORM FOR DISTRIBUTED PUBLISHING AND MANAGEMENT OF HYPERMEDIA OVER WIDE AREA NETWORKS," LINDA T. DOZIER, ET AL. 1. NaviPress and NaviServer: A Client-Server Publishing System for the World-Wide Web, by Linda T. Dozier 2. Draft of a user manual for NaviPress and NaviServer 3. Sample source code for NaviPress and NaviServer 23 NaviSoft NaviPress and NaviServer A Client-Server Publishing System for the World-Wide Web Linda T. Dozier NaviPress and NaviServer form an seamless access to both local and integrated client-server network remote Web pages, allowing publishing system for creating content, remote authoring over the Internet; managing information, and developing "NaviLinks," to easily translate text applications on the World-Wide Web. into hypertext and automatically Our software is intended for companies identify related pages; and enterprising individuals who want to create and maintain innovative, an information architecture for operational Web applications. management and control of assets; NaviPress and NaviServer provide the HTML as a general-purpose, forms- following unique combination of oriented interface to a DBMS that services: eliminates the need for CGIs • the "MiniWeb," to graphically (common gateway interfaces); visualize and organize a collection an easy-to-use hierarchical access of pages into a document; control and cost model; • integrated WYSIWYG authoring example "Blueprints" that function and browsing of Web pages like Microsoft Wizards for the without typing HTML (hypertext Web; markup language) tags or names of extensibility, to implement custom URLs (uniform resource locators); services. ©1 95 NaviSoft, March 1995 An America Online Company 1. Introduction This paper explains the features and architecture of NaviPress and NaviServer. We intend the discussion for technical personnel who are interested in a description of client and server functions and an explanation of the internal architecture. The introduction explains why we developed our products and how our customers will use them. The rest of the discussion explains the products' features, scenarios for their use, and the underlying architecture. 1.1. Tools Available Today for the World-Wide Web The World-Wide Web (WWW) has fueled the explosive growth of the Internet and the emerging software and services industries that surround it. Today there are 27,000 Web sites, and the estimated number of sites doubles every 53 days 1 . Most new software products for the net are cruiseware, commerce servers, or stand-alone hypertext markup language (HTML) editors 2 . Cruiseware comprises client applications that help users access Internet services — electronic mail, ftp, news, gopher, and the Web. Commerce servers address the need to securely transfer credit card numbers, or other proprietary or sensitive information, and to negotiate payment. Stand-alone HTML editors are desktop applications that produce HTML output; examples include Microsoft Word and its Internet Assistant, Cyberleaf, and HotMeTaL While all these tools are useful, none of them focuses on the problem of creating and maintaining a full-fledged Web application — a server that includes pages, forms, access control, regular maintenance, and processing of data collected over the Web. Today, developing an application that provides or collects information through the Web requires a variety of skills — knowledge of the hypertext transfer protocol (http), HTML, common gateway interface (CGI), Unix, and programming in C, Perl, or SQL. Cruiseware provides excess to the Web once someone has put up the pages, commerce servers assure a secure channel of communication between client and server, and a 1 A. Cortese, J. Verity, R. Mitchell, and R. Brandt, Cyberspace: crafting software that will let you build a business out there, Business Week, n3413, Feb 27, 1 95. 2 See O. R. Tabibian, Electronic businesses (software for building a World-Wide Web server), PC Magazine, v 14, n3, Feb 7, 1995. ©1995 NaviSoft, March 1995 An America Online Company stand-alone HTML editor produces a file of HTML output on the desktop. Despite all this software, the information provider still needs a programmer to put all the pieces together into an application. Moreover, none of these tools provides a framework expressly designed for developing and maintaining applications. 1.2. The Niche for NaviPress and NaviServer NaviPress and NaviServer are an application development platform for the World- Wide Web. They form a client-server publishing system and extensible information system that make it easier to create content, manage assets, and process information. Our software is for the content creator and provider. It helps people establish and maintain Web servers more easily than they do today. Using NaviPress and NaviServer, an infopreneur — an enterprising individual or company who is moving advertising, marketing, support, and sales activities to the Web — can build rich applications, without detailed knowledge of protocols, markup languages, and operating systems. Together NaviPress and NaviServer provide an interactive environment for building applications. Although it is possible to use either NaviPress or NaviServer alone, they are part of a client-server product suite and work best together. The client, NaviPress, has a point-and-click interface for creating, editing, and linking applications. The server, NaviServer, supports these applications by servicing requests, managing content, and providing an information architecture. Classic applications that can be developed using our tools include: • a corporate "home page" with linked text, image maps, and forms that the reader can search; • a customer support system for collecting customers' feedback and distributing information about products; and • a Web directory service that catalogs and indexes interesting sites. Because NaviSoft' s tools greatly simplify the development of Web applications, they let us reach and cultivate a larger, more diverse group of content creators and providers than the Unix programmers and system administrators who make up that community today. Typical customers for our products include: • Internet consultants selling setup or hosting services; • creative agencies developing Web pages for clients; • in-house corporate management information departments responsible for setting up and maintaining a Web presence; • publishers using the Web as a distribution channel for electronic content; March 1995 ©1995 Navisoft, An America Online Company • merchants using the Web to advertise and provide products for sale; and • small businesses and individuals who want a Web presence. With the introduction of NaviPress and NaviServer, NaviSoft brings a new product category to the World-Wide Web. There are many useful and exciting products available for the Internet today, but none have focused exclusively on making it easier to create and maintain Web applications. In the next three sections we present key features of our tools, explain how to use them to build applications, and describe the internal architecture. 1.3. Availability NaviPress is available for Windows 3.1, Macintosh System 7.x, and X/Motif. NaviServer is available for Solaris 1.x, Solaris 2.x, Solaris Intel, HP UX, Windows NT 3.5, IRIX 5, and OSF/l. 2. Key Features of NaviPress and NaviServer NaviPress and NaviServer uniquely encompass features to form a comprehensive, end- to-end capability for corporate information officers, information providers, publishers, graphic artists, and consultants. Other individual products on the market carry out some of our functions, but no other product combines the full range of features in NaviPress and NaviServer. Our tools combine: • integrated WYSIWYG authoring and browsing of Web pages without typing HTML tags or names of URLs; • seamless access to both local and remote Web pages, allowing remote authoring over the Internet; • the "MiniWeb," to graphically visualize Webs and organize collections of related pages; • "NaviLinks," to easily translate text into hypertext; • an information architecture based on a database management system (DBMS) and information retrieval (IR) engine that complements a hypertext-based navigation architecture; ©1995 NaviSoft, March 1 95 An America Online Company • automatic generation of HTML forms and the use of HTML as an interface to a DBMS to extend the reach of database applications to wide-area networks; • hierarchical access control and cost model that are consistent with the structure of the Web; "Blueprints" that function like Microsoft Wizards for the Web to help get applications up and running quickly; • extensibility, to implement custom services. Author Web pages without typing a single HTML tag. NaviPress provides a fully interactive interface for creating Web pages, including image maps and forms. It is similar to a word processor, but is especially designed for creating HTML. It supports features unique to HTML, such as links, image maps (images with interactive regions that link to URLs), and forms. It produces HTML output that structures documents, but leaves the presentation (fonts, alignment, etc.) under the control of the reader's application. The interface for creating pages is point-and-click, so there is never a need to type any HTML tags or URLs. Open pages without knowing exact URLs, and publish pages, or collections of pages, with the click of a button. NaviPress is a networked application. Unlike stand¬ alone HTML authoring packages that write files to the desktop, NaviPress lets you work on files that exist on your desktop machine, or in a remote location served by a local or wide-area network. You can edit a file on the desktop, or edit a file on a server over the Internet. When you select Open..., you can pick files from your local drive or from the file system of the server. Unlike other browsers, where you must know the exact path of the URL to open, you can browse the file system of a NaviServer using the same interface you use to browse files on your local disk. You can open a directory and see a list of its contents, or traverse the directory structure of a remote Web server using a point-and-click interface from your desktop client. Similarly, when you want to save a page, you can write it to your local file system or write it to the server. You can place the file in the right location in the directory structure of your Web server, or you can edit an existing page and just hit Save to write changes over the net to the original location of the page. With this interface you do not have to remember exact URLs for reading or writing. You can Open, Save, and Save As... to the server using the same interface that you use to manage files on your local disk. Immediately place your work into the Web through seamless integration of browsing and authoring. With our Web browser, you can open an URL, point the cursor into the middle of a page, click to make a change, and then select Save to publish it to a server thousands of miles away. With NaviPress you can author while you browse and browse while you author, seamlessly using the same application, same windows, and same interface. The only distinction between authoring and browsing is whether you modify a page or just look at it. There is no switching between view mode March 1995 ©1995 Navisoft, An America Online Company and edit mode, nor is there a multi-step procedure where you create the HTML, write the output to a file, move the file to a Web server, and then load the file into a browser to see what it looks like and test the links. The authoring tool is a browser, and the browser is an editor. Visualize and organize hypertext connections using MinϊWebs. The basic unit of information on the Web today is a page. Whether browsing or authoring, you view a single page, and you must scroll through it, perhaps moving the cursor over the links, to follow the hyperlinks. Pages are unrelated except for references through URLs. The Web has no inherent mechanism for organizing sets of related pages into groups that share common properties and can be treated as a unit. We have introduced a construct, the MiniWeb, for organizing and visualizing related Web assets. A MiniWeb is a collection whose internal links are relative and whose external links are absolute. MiniWebs have ownership, can share common properties, can be moved without breaking links, and can be viewed graphically. Both our client and server support the ability to operate on collections, rather than just pages. The MiniWeb window in NaviPress is a visual aid that is useful for browsing and authoring. When browsing, MiniWebs give you a picture of the forest instead of the trees. To view a page double-click on it, or drag and drop the page from the MiniWeb window into a page window. As you author pages, NaviPress automatically places them within a MiniWeb. As you create content and links, the MiniWeb shows you active status of your work, displaying your Web as you build it. Make all your links without typing a single URL. NaviPress offers a fast, error-free way to create hyperlinks using the clipboard. While viewing a page, whether authoring or browsing, you can select Copy URL to put the URL of the page into the clipboard. Then you can paste it into a MiniWeb to graphically visualize the page and all of its links, or you can highlight a selection of text as an anchor and paste the URL to make a link, or you can paste the URL into fields in dialog boxes to make regions in an image that link to other URLs. You can copy and paste the URL of any page in the World-Wide Web, not just the pages you own or have just created on your desktop. You can author a page in one window, browse the Web in another, and use copy and paste to create links from your page to places throughout the World-Wide Web. It is fast, works both locally and across the network, and reduces errors because you type no URL names. The ability to seamlessly integrate browsing and authoring, copy and paste URLs, and access the file system of remote servers immediately places you and your work within the context of the Web. With NaviPress you work on the Web itself, not just on creating HTML page-by-page. Turn plain text into hypertext automatically using NaviLinks. Most content on the Web is not originally created as hypertext. There are news articles, specifications, product information, and brochures that start out as linear text that the creator or editor must modify and translate for the Web. While various conversion processes exist to put text into HTML, these conversions put few, if any, links into the body of the text. ©1995 NaviSoft, March 1995 An America Online Company "NaviLinks" is our feature that helps you create hyperlinks. They take an input file (plain text or HTML), apply algorithms that understand natural language to select potential anchors, and then use information-retrieval algorithms to find other pages related to the suggested anchors. An interactive interface lets you look at automatically generated hyperlinks and then apply or discard the suggestions. The combination of NaviLinks, authoring, and publishing lets you quickly turn plain text into richly connected, nicely formatted hypertext. Control your content using information management technology. The Web has a great navigation architecture, but it lacks an information architecture. Imagine using a library whose main search mechanism is to pick up a book and then follow references from book to book. Imagine also that the books' titles relate only vaguely to their content. This is an alarming, but accurate analogy to the World-Wide Web today. Web pages are strewn throughout file systems all over the world with no relationship to each other except through URLs. Although there are now search tools to find words in titles of Web pages 3 , there is no analogy to the rich indexes into the traditional journal literature, and there is no way to keep track of the content that you manage. On a small scale this may not matter, but for commercial applications where content is your primary asset, an information system to manage your content is vital. Central to the NaviServer are information technologies that it uses to catalog and manage content. When you publish to a NaviServer, it automatically indexes the full text of pages. In addition, you can run the server in a mode where it builds an archive that keeps a history of all changes. A Web-based newspaper, magazine, or newsletter could use this feature to automatically archive "back issues." As daily, weekly or monthly articles are published for each section, the server automatically archives the previous version. The information management system built into the NaviServer describes the content of a specific server or content found throughout the Web. The mechanism is not exclusive. You can attach any type of description, or many descriptions, to any URL. No matter how many views you have defined for a set of pages, the server stores them only once. For example, you could create catalogs for What's New, What's Cool, and What's Popular. Some URLs are new, cool and popular, while others may be just new or just cool. Users access these catalogs, but an administrator might catalog some of the same URLs by author, title, subject, modification date, and frequency of access. The substrate of information that sits beneath your pages can be accessed using all the power of relational and full-text search engines, including similarity, Boolean, and relational search operators. NaviServer gives you the full power of a database and its utilities to manage your server's information content. 3 e.g. http://www.yahoo.com March 1995 ©1995 Navisoft, An America Online Company Create database applications for the Web without writing a single line of code. NaviPress and NaviServer provide a general purpose, forms-oriented interface to a DBMS over the Internet. NaviPress and NaviServer let you create database tables by filling in a form with information about the table, then NaviServer automatically generates an active HTML form that maps to the DBMS. You define the fields, NaviServer creates the HTML form, and NaviPress' authoring ability lets you customize the appearance of the form and place it into your Web. Through point-and- click, add your artwork, modify text, and then paste the form into your Web. Instantly the form can be used to insert, update, delete, or search using a full range of database technology. You have an active HTML form, without writing a single line of code. You can create forms to collect customers' comments, accept product orders, register for seminars or training, track problem reports, etc., and you have wide-area distributed access to the database through the World-Wide Web. Administer hierarchical access control and cost accounting using simple forms interfaces. Built into the NaviServer are hierarchical access control and cost accounting. You can set user, group, or world permissions for read and write at any level in the hierarchy of a Web server. Lower levels inherit permissions from higher levels, so it's easy to set up a server where separate groups maintain different parts, or where some areas are publicly accessible and others are protected. Through a forms interface on the client, you set access controls. The NaviServer thereby allows remote or local administration, even by people unfamiliar with server administration. There is an analogous way to associate costs with operations on the server. You can use a forms interface to set the cost for an operation on an URL. Every request for the operation incurs a cost set by the administrator, and the server records the transaction in the database. You can review costs, process them, or export the transactions to an accounting and billing system. Quickly start building application using Blueprints. To make application development even easier, NaviServer includes a set of Blueprints, example applications that serve as templates for development, like Wizards for the Web. A Blueprint is a MiniWeb that includes default content, structural relationships, common stationery, database templates, and forms. Example Blueprints include a customer support system, personal home page, and Internet directory. The quickest way to bring up your own customer support system or Internet directory is to open a Blueprint, then use NaviPress to modify the stationery, set your own style, modify the default content, add your own content, perhaps edit the structure and add some database forms, and publish. Blueprints help you get going quickly by providing a ready infrastructure, so all you need to worry about is content specific to your application. Build a custom NaviServer by adding your operations. NaviServer is a platform for the content creator and provider, who can use it immediately to author content, organize servers into MiniWebs, administer the server, build forms-based database applications, or customize Blueprints. NaviServer is also aframeworkfor the system ©1995 NaviSoft, March 1995 An America Online Company developer, with an architecture designed for ease of development. The developer can customize the NaviServer in three ways, either by using our built-in processing operations, adding new operations through our library, or, because the NaviServer has an information-centric architecture, by developing database applications that process the content of the NaviServer in the DBMS. There is a consistent, open interface for requesting operations, so any http-compliant client can access new operations. 3. Sample Scenario: Using our Tools to Build a Customer Support System In this section we illustrate how to use the capabilities described in the previous section by building a customer support system on the Web. In our example, NewCo is a medium sized, high-technology business that wants to move sales and support activities to the Web. NewCo 's objectives for their Web site are to establish a corporate presence, electronically distribute product information, attract customers, advertise products and services, and accept orders and collect customers' comments. In our example, we start by using a NaviSoft Blueprint. We briefly walk through illustrative steps to modify me Blueprint, add new content, create a support database, and publish the application. Exhaustive scenarios are beyond the scope of this paper, so we focus on a narrow thread, bypassing examples of other interesting features such as NaviLinks and server administration. 3.1. Selecting a Blueprint We start by opening a standard Blueprint and create our own local copy. All changes are made to the local copy, which we publish to the server at the end of the scenario. To make a your copy of a Blueprint: 1 . Go to the help menu and select Examples. 2. Select the Customer Support link. 3 . Select Save As... and write a copy to your local disk. March 1995 ©1995 Navisoft, An America Online Company Figure 1. Customer support Bluepπnt A Blueprint is a predefined MiniWeb that includes sample pages, artwork, forms, and structural relationships between pages. You can use the organization offered by default, or make whatever changes you like. Figure 1 shows the customer support Blueprint, an example of a MiniWeb that shows some icons and links. The icons indicate the type and status of an asset. Variations of the icons reflect their current status — e.g., saved, unsaved, inside the MiniWeb, reference to an external asset, etc. ©1995 NaviSoft, March 1995 An America Online Company 10 3.2. Browsing Using a MiniWeb The first thing you would likely do with a Blueprint is to look through its pages. Using a MiniWeb you do not have to traverse links to get to the right page. Instead, the MiniWeb shows all assets and their relationships, so you can point-and-click or drag- and-drop to immediately view what you want. There are three ways to look at pages in a MiniWeb: 1 . Move the cursor over a page icon in the MiniWeb and double-click to open a window for authoring on the page. 2. Browse in the usual fashion by following links, or go back to the MiniWeb window and double-click on another icon to open another page window. 3 . Select an icon from the MiniWeb and drag-and-drop the page icon from the MiniWeb to the page window. This replaces the content of the page window with the dropped object. NaviPress lets you open many page and MiniWeb windows while you work. Copy- and-paste or drag-and-drop work from page to page, MiniWeb to page, page to MiniWeb, or MiniWeb to MiniWeb. NaviPress keeps a global history of your actions, and each page window has its individual history. 3.3. Creating a Form You can customize a Blueprint using the authoring capabilities of NaviPress. You can add new pages, import existing assets, create links, or change what NaviServer provides by default. As an illustration, we show how to add a form to the Blueprint. You create forms by using a fill-in-the-blanks interface, and then you customize them using NaviPress. They are immediately useful for data entry, update, and queries without any further modification. In our example we create a form for collecting customer comments. 1 . Select General... from the Administration item of the Tools menu. 2. Select Create Table from the server administration page. 3. Complete the form shown in Figure 2, describing the table and its columns. The table is called comments and it has fields for custname, address, e-mail, phone, fax, and comments. March 1995 ©1995 Navisoft, An America Online Company 1 1 Figure 2. Form for collecting customers' feedback 4. The NaviServer checks the form for valid inputs, adds information to the server for processing the form when it is used, and automatically creates a default form, shown in Figure 3, for enteπng data and searching the contents ©1995 NaviSoft, March 1995 An Amenca Online Company 12 The default form generated by NaviServer is a page that can be modified using NaviPress. In our example, we modify the form as follows: Figure 3. Default form created by NaviServer for collecting customers' feedback March 1995 ©1995 Navisoft, An America Online Company 13 Figure 4. Customized form for collecting customers' feedback a ) Replace the title with Send Us Your Comments. Select the default title, press cut on the toolbar, enter a new title, select the text, and from the Format menu select Headings and Hdg 1. (or use ctrl+1 as a shortcut) to make it a level 1 heading. b) Select the default instructions, press cut on the toolbar, and replace them with your own. ©1995 NaviSoft, March 1995 An America Online Company 14 c ) Select trim text in front of the fields and make it more descriptive. d ) Cut the default artwork, and select Image... from the Elements menu to import your logo. Figure 4 shows the finished form. Forms created with NaviPress work immediately. You can test a new form by entering data into the fields and pressing Enter Data. This adds the information to a database, and you can verify the insert by searching the database or pressing verify link in the message returned by Enter Data. 3.4. Adding the Form to the MiniWeb and Creating a Link There are several ways to add assets to a MiniWeb. You can use Import, Save As..., or Copy and Paste. In this part of the scenario we add the comment form to the MiniWeb and link it to a page in the customer support system. 1 . Select Save As... from the File menu. Give the form a name, and save it into your local MiniWeb. 2. To create a link from the Help Desk page to the customer comment form, move the cursor over the icon for the form, and select Copy URL from the Edit menu. Open the Help Desk page by double-click or drag and drop, highlight the text of your anchor, and select Paste URL from the Edit menu. This creates the link; you can use it immediately to make sure that it works. 3.5. Publishing to the Server Once you have made all me changes you want and are ready to publish the results, simply save the MiniWeb to the server. Open, Save, and Save As... work the same either locally or remotely in NaviPress. You can browse the file system of the server just as you would your local disk, and save pages and whole MiniWebs with the push of a button. 1 . Select Save As... from the File menu of the MiniWeb window. 2. Select the server from the dialog box shown in Figure 5. You can browse through your local file system by selecting the C: drive, or the file system of the server. Look for the right place by double-clicking on names in the directory box. 3 . Once you have found the location and given die MiniWeb a name, press Save. NaviPress collects all the assets in the MiniWeb, modifies the links so they will work correctly in the new location, and sends the collection to the NaviServer. NaviServer checks access controls, indexes all pages, logs the event, and puts the pages in the right location in the file system. March 1995 ©1995 Navisoft, An America Online Company 15 MMWbb Location: Save http: //navisof . com: 8001/1 Cancel Directory: http : //navisoft J _glnmpse_fuenaines _g-i_τιρse_tndex _gUmpse_messages _gHmpse_partitions _g_tπpse_statistics μ z Drives / Servers / MmiWebs: http : //navisoft . com: 8001 Lm Figure 5. Dialog box of directories and files on remote server 4. Overview of the Architecture 4.1. Client-Server Interaction NaviPress and NaviServer are a client-server application communicating through the hypertext transfer protocol (http). All requests and responses between the client and server are transferred through http. NaviPress sends requests to a NaviServer using GET, PUT, POST, BROWSE, and DELETE methods, and the NaviServer returns results using standard http return codes and special content types for NaviSoft-specific data. Because we adhere to http for all client-server interaction, both client and server are "open." Any http-compliant client can access most NaviServices, and NaviPress can be used with other http servers. ©1995 NaviSoft, March 1995 An America Online Company 16 Table 1. Examples of NaviServer operations NaviPress requests services from the NaviServer through a method and an URL, some are ordinary URLs, and some are special URLs that map to server functions. If a request is not immediately serviceable — e.g., GET a page for browsing — the NaviServer checks to see if the URL contains a special prefix, a registered operation that maps to server-specific processing code. The NaviServer comes with about 20 installed operations, listed in Table 1, that implement publishing, administration, information retrieval, and document management functions for our client and server. These URLs take the general form /prefix/operation/arguments, where the arguments are an arbitrarily long string that is passed to the operation. The NaviServer looks for registered prefixes, determines that the operation is a special NaviService, and passes the request to the appropriate process. We designed the NaviServer so that custom services can be added easily; application developers can register new operations with their own unique prefixes. March 1995 ©1995 Navisoft, An America Online Company 17 Figure 6. NaviPress internal structures Since we use a standard, open protocol to communicate between client and server, it is possible for vendors of other desktop HTML authoring tools to write an interface that publishes to NaviServers. 4.2. NaviPress As shown in Figure 6, NaviPress operates on two primary objects: pages and MiniWebs. A MiniWeb is composed of zero or more pages and zero or more assets (e.g., images). For each internal representation of a MiniWeb, NaviPress displays one view in one MiniWeb window. You can, however, have many open MiniWebs at any given time. Each page has zero to many views displayed, and each page window has one or more views associated with it, as Figure 7 shows. Pages can be local, from the net, edited, only viewed, and a page may have more than one view. Figure 7. Relationship between the page window and page views ©1995 NaviSoft, March 1995 An America Online Company 18 Platform Independent Ul Display Server Communications layer Figure 8. Functional components of NaviPress Figure 8 shows the functional components of NaviPress. A brief description of each component follows: • The interface layer of the architecture is a platform-independent user interface, built using a library of widgets — buttons, scroll bars, and dialogs — implemented on a portability layer that provides cross-platform compatibility between Macintosh, Motif, and Windows. The interface sees user events and executes appropriate functions. • The display service renders page and MiniWeb views. It interacts with the browse, author, and MiniWeb services. • Browse implements standard browser functions. • Author is the HTML editing engine. Authoring manipulates the internal page structure. • The MiniWeb service implements all MiniWeb functions. It interacts with the display, author, and file services. • File is responsible for operations on files (Open, Save, Save As..., Import, etc.), and along with server and browse services, sends messages to the communications layer. • Server handles any special processing required to request or process results of NaviServices. The communications layer asynchronously handles events that require client-server interaction. It is capable of managing multiple, simultaneous requests and responses. 4.3. NaviServer The architecture of the NaviServer (Figure 9) consists of communications, run, operations, library, and component layers. The Communications Layer is an asynchronous http server that creates, continues, runs, and disposes of connections. When the server accepts a TCP connection, it March 1995 ©1995 Navisoft, An America Online Company 19 Communications Layer Run Layer Library Layer Operation Layer Component Layer Figure 9. NaviServer architecture creates a connection structure (NS_Connection), with I O buffers, and maintains the connection's state. Multiple connections can exist, and clients can read from and write to them without blocking. Once a connection is accepted and the NS_Connection established, the server reads the http request, header first and then die body. Once it has read the request and the socket is ready for writing, the Communications Layer runs the connection. The interface from the Communications Layer to the Run Layer is an NS_Connection structure. The Run Layer: • Determines what operations to run. Categories are: - unknown, which produces an error; - a NaviSoft-registered operation that comes installed with our server; - other, new operations registered by developers; or - default, a standard http operation such as GET or PUT. ©1995 NaviSoft, March 1995 An America Online Company 20 • Checks permissions stored in the database to see if the user is authorized to run the request. Operations can be: - allowed; - forbidden, an operation that cannot be executed; or - unauthorized, where is operation is allowable but the user is not authorized. • Executes the operation, either directly or, optionally, asynchronously in a child process. Examples of asynchronous operations include: - GetRemotePage; - IndexRemotePage; and - CGIs. The Operations Layer contains all NaviServices. There are four types of operations: • NaviSoft operations include those listed in Table 1, among others. They make up the bulk of the NaviServer' s information management services. • Default operations operate directly on the file system and do not require access to the component layer. These include standard http requests to GET, PUT, POST, DELETE, and our new method BROWSE. These affect the file system and have been extended to operate on MiniWebs as well as single pages. • Tel operations are functions written in the Tel scripting language 4 instead of C. Many of our administrative functions are Tel procedures (e.g., archiving and the ability to create and drop database tables). Tel operations, written using a set of Tel commands that are analogous to our C libraries, provide database, HTML, and file system utilities. Because Tel is a popular scripting language, these operations are simpler and faster to implement. They can be added to the server at run-time without requiring compilation. • Other operations are registered by our developers, with their own unique prefixes. A mechanism for extensibility, they let the developer identify new operations and add special code. The Operations Layer is built on the Library Layer. • The Tel command layer provides Tel procedures that mirror the underlying C library. There are Tel procedures for database access, NS commands such as logging and registering new operations, and functions to return HTML. This layer provides access to C libraries through Tel, so Tel developers have a J. K. Ousterhout, Tel and the Tk Toolkit, A dison- Wesley, 1994. March 1995 ©1995 Navisoft, An America Online Company 21 powerful set of procedures to build upon. For example, there are Tel procedures to open databases and execute SQL commands. • The C library layer includes routines that: - provide vendor-independent access to DBMS and IR functions; - provide continuations, non-blocking reads and writes, and return functions; - help create and manipulate HTML structures; - manage NaviLinks; and - manage memory and forms, etc. The Library Layer sits on the Component Layer, which has a database management system, information retrieval engine, natural language processing, and Tel. • Developers can extend the server using the DBMS directly through alerts, gateways, DBMS development, report writers, etc. • They can write and register new operations by developing on the Library layer with Tel scripts or C subprograms, or they can write CGIs. 5. Enhancing and Measuring Performance 5.1. Enhancements We have implemented performance enhancing strategies on both the client and the server. On the client the features include: • Asynchronous communications allow multiple tasks to proceed concurrently.. • Local caching of images, pages, and authorization data enables rapid access to recently-used data. Performance features of the server include: • Asynchronous communications continue to accept requests as long as the server is able to process them independently. The server can work on numerous requests at any given moment. © 1995 NaviSoft, March 1995 An America Online Company 22 • Caching of frequently used information reduces the need to go to disk or the DBMS for information. • Deferred chores defer write operations to times when the server is idle. If the buffer for deferred operations fills, the server blocks until pending writes are flushed. • Operations that take a long or unpredictable amount of time are forked and run in an independent process. Examples include indexing remote pages. 5.2. Measurements of Performance We have measured the performance of our server in handling simple page requests, and we have compared NaviServer on Unix, Windows NT, and Solaris Intel to other servers — Netsite, CERN, and EMWAC (European Microsoft Windows NT Academic Centre). Because simple page requests are the only function that other servers implement, we could not compare performance on publishing, NaviLinking, forms generation, etc. We did compare the performance of database select operations by using the CGI for Netsite. The first set of tests measured the servers' ability to handle simple page requests from multiple clients. Five clients simultaneously fired requests for pages at the server; each trying to sustain ten simultaneous active connections. We varied the page size in the test: small pages (1.5 Kbytes), large pages (60 Kbytes), and mixed pages (three clients requesting small pages, two requesting large pages). We ran the tests on a local network, with no other traffic, in the following configurations: • NaviServer, Unix operating system, on a Hewlett-Packard 715/80 with 64 Mbytes memory; Netsite, Unix operating system, on the same H-P 715/80 as above; CERN http daemon, Unix operating system, on a Sun Sparc 10 with 64 Mbytes memory; • NaviServer, Solaris Intel operating system, on a laptop 486DX50 with 32 Mbytes memory and a Xircom Pocket adapter interface; • NaviServer, Windows NT operating system, on an Intel 486 machine with 40 Mbytes memory; • EMWAC http daemon, Windows NT operating system, on the same 486 machine as above. Four clients were Sun Sparc5; one was a Sparc20. Table 2 shows the results. March 1995 ©1995 Navisoft, An America Online Company 23 Table 2. Performance statistics — connections per second for servicing page requests We configured the Netsite server to run with 16 processes and to resolve IP addresses to host names. Netsite offers these as configuration options, but give imprecise guidance about how the values affect performance. In our tests, resolving IP addresses to host should not affect performance, because the hosts did not vary and the names were probably cached. The NaviServer always resolves host names, without hindering performance, because name lookup for logging is deferred to the background chores process. Figure 10 shows that selecting 16 processes is near the optimum configuration for Netsite on our test machine. It is difficult to select the optimal configuration without a load model and rigorous testing. The NaviServer' s performance under Unix compares well with Netsite 's. NaviServer is notably faster, 17%, when the page sizes are mixed. For large pages the performances of all configurations except the CERN http daemon and the Solaris Intel are close. The CERN server is slow for all page sizes, and the Xircom adapter on the Solaris Intel is slow in transferring large pages. NaviServer on Windows NT, on an ordinary 486 machine, services requests more quickly than either NaviServer on Unix or Netsite (which is not available yet for Windows NT). However, Windows NT drops connections, whatever the server. Finally, NaviServer running on a laptop machine provides adequate performance for applications whose page sizes are small. Usually the operating system is the limiting factor in performance for simple requests. Figure 10 shows how the performance of Netsite varies with the number of processes running. It shows that the kernel of the Unix operating system on the H-P 715/80 can accept no more than about 80 connections per second. As we increase the number of ©1995 NaviSoft, March 1995 An America Online Company 24 Figure 10. Variability of Netsite connections with number of processes running processes running beyond 20, performance degrades; when we tried to implement 50 processes, the machine ran out of process space and we could not even run a process to kill the Netsite service. Without modifying the operating system itself, we cannot improve performance beyond this limitation. The main bottleneck to handling simple requests is the kernel of the operating system and its ability to accept TCP connections and read requests. Hence the primary target for future optimization is the way http uses TCP, and to modify or make enhancements to the kernel of the operating system. The second performance test used a simple database query: examine the list of permission codes for a page (select * from ns_permissions). On the NaviServer this is a straightforward search query. For Netsite we wrote the same query as a common gateway interface (CGI). We conducted two tests. Table 3 summarizes the results. In test DB 1 five clients each kept a queue of ten requests (queries), and the server answered these as quickly as it could. In a simpler test, DB2, there was only one client, which held just one query in its queue. Table 3 illustrates the power of the NaviServer DBMS interface, whether it is running under Unix on a powerful workstation, under Windows NT on a 486-based machine, or on a laptop. Under Unix, it services the simple database query 4 times faster than Netsite, and neither drops connections nor fails to service the queries when there are multiple queries in the queue. Windows NT is also very fast, but it drops connections March 1995 ©1995 Navisoft, An America Online Company 25 Table 3. Performance statistics — connections per second for a simple database query when the queue has multiple requests. Finally, NaviServer on a laptop under Solaris Intel is about twice as fast as Netsite on a Unix workstation. 6. Conclusion NaviPress and NaviServer together have the following unique features: • The MiniWeb unifies pages into a collection and provides a graphical representation for visualization, organization, and manipulation. The user can copy a set of pages to another client or server and preserve all links. • An integrated browsing and authoring tool provides client-server hypertext publishing on the Internet. NaviPress makes editing and browsing functionally and visually equivalent, and provides seamless access to local and remote file systems. NaviServer incorporates a database management system. With NaviPress, you can automatically create forms for collecting information from users that the NaviServer can then process with a powerful DBMS. Forms are immediately useful without any additional intervention or development by the user. NaviLinks let you automatically create links between related pages. Natural language processing and statistical algorithms generate anchor terms and phrases in a selected page. Then for each anchor the NaviServer identifies candidate related pages, and you can accept or reject each suggested link. Finally, the content creator and provider can extend the NaviServer' s functions through interfaces in three different layers for the applications programmer: the Operations Layer, the Library Layer, and the Component Layer. ©1995 NaviSoft, March 1995 An America Online Company 26 7. About the Team Linda Dozier is Vice President and Chief Technologist for NaviSoft. She has been with NaviSoft since David Cole, now President of America Online' s Internet Service Company, founded it in 1993. NaviSoft focuses on network publishing tools and especially on publishing for the World-Wide Web. The core engineering team for NaviPress and NaviServer consists of George Williams, Dave Long, and Dave Bourgeois on client development, Karen Brady on interface design, and Doug McKee and Jim Davidson on server development. March 1995 ©1995 Navisoft, An America Online Company 51 Table Of Contents Preface P-l P.I Introduction P-l P.2 Audience P-l P.3 Legend P-2 CHAPTER 1 Introduction 1-1 1.1 About the Product 1-1 1.2 Documentation Structure 1-2 CHAPTER 2 Browsing 2-1 2.1 Introduction 2-1 2.2 Starting NaviPress 2-1 2.3 Page Windows 2-1 2.3.1 Browsing 2-2 2.3.2 Extras 2-3 2.3.2.1 Reloading Page 2-3 2.3.2.2 Hot List 2-3 2.4 Exiting NaviPress 2-4 CHAPTER 3 Authoring 3-1 3.1 Introduction 3-1 3.2 Creating a Web Page 3-1 3.2.1 Titling Your Page 3-2 3.3 Simple Editing 3-2 3.3.1 Formats 3-2 3.3.1.1 Special Styles 3-3 3.3.1.2 Headings 3-3 3.3.1.3 Lists 3-3 3.3.1.4 Format Borders 3-4 3.4 Importing Graphics 3-4 3.5 Adding to the Page 3-5 3.5.1 Copying Text from Other Pages 3-6 3.5.2 Creating Links 3-7 3.5.3 Creating Anchors 3-7 3.5.4 Image Maps 3-8 3.5.5 Copying URLs 3-9 NaviPress and NaviServer 52 Page i Table Of Contents 3.6 Style Sheets 3-9 3.7 An Example Page 3-10 3.8 Publishing Your Page 3-10 CHAPTER 4 MiniWebs 4-1 4.1 Introduction 4-1 4.1.1 Terminology -. 4-2 4.1.2 MiniWeb Icons 4-3 4.2 Tutorial 4-3 4.2.1 Copying the MiniWeb 4-3 4.2.2 Adding Your Page 4-4 4.2.2.1 Fixing the Images 4-4 4.2.2.2 Fixing the Page Links 4-5 4.2.2.3 Linking to the Home Page 4-5 4.2.3 Merging MiniWebs 4-5 4.3 Feature Overview 4-6 4.3.1 Color Coding 4-6 4.3.1.1 Icon Color 4-6 4.3.1.2 Link Color 4-6 4.3.2 Double Clicking on Icons 4-7 4.3.3 Drag and Drop Features 4-7 4.3.4 Filling in Relative Links 4-7 4.4 Editing With MiniWebs 4-8 4.4.1 Copying URLs 4-8 4.4.2 Deleting Icons 4-8 4.4.3 Saving 4-8 4.4.4 Setting the Home Page 4-8 4.4.5 MiniWeb Button 4-8 CHAPTER S The NaviServer 5-1 5.1 Introduction 5-1 5.2 Quick Start 5-1 5.2.1 Command-line Options 5-2 5.2.2 rc.local 5-2 5.3 Searching the NaviServer 5-3 5.3.1 Searching Database Tables 5-3 5.3.1.1 The Body of die Search Form 5-3 5.3.1.2 More on the Search Form 5-4 Page ii 53 NaviPress and NaviServer Table Of Contents 5.3.2 Searching for Pages 5-4 5.3.2.1 Searching the ns_default_collection . . . . 5-4 5.3.2.2 Searching Medadata Tables 5-4 5.3.3 Hitlists and Hittables 5-4 5.3.4 Highlighting and More Like This 5-5 5.3.4.1 Highlighting 5-5 5.3.4.2 More Like This 5-5 5.4 Entering Data and Updating It 5-5 5.4.1 Typechecking 5-5 5.4.2 Dates and Times 5-5 5.5 Creating and Deleting Tables 5-6 5.6 Customizing NaviServer Forms 5-8 5.7 Examples: Building a Database Application 5-9 5.7.1 Creating a table for Problem Reports 5-9 5.7.2 Customizing Form Appearance 5-10 5.7.3 Pointing to Forms 5-11 5.8 NaviLinking 5-11 5.9 Security 5-11 5.9.1 Users and Groups 5-11 5.9.2 Protecting URLs 5-12 5.9.3 Using NaviPress to Set Permission 5-13 5.10 Costs 5-13 5.10.1 Setting up costs 5-13 5.10.2 Viewing charges 5-14 5.10.3 Using NaviPress to Set Costs 5-14 5.11 Example: Managing Documents 5-14 5.11.1 Searching through publications 5-14 5.11.2 NaviLinking 5-15 5.11.3 Publish 5-15 5.11.4 Setting Permissions and Costs 5-15 5.12 Describing Pages 5-15 5.13 Archive Versioning 5-16 5.14 Logging 5-16 5.14.1 Access log 5-16 5.14.2 Error log 5-16 5.15 NaviServer System Tables 5-17 NaviPress and NaviServer 54 Page iii Table Of Contents APPENDIX A Page Window, Menus, and Icons A-l A.1 NaviPress Page Window A-l A.l.l Toolbar A-2 A.1.2 Overview of Menus A-3 A.2 The File Menu A-4 A.2.1 New MiniWeb A-4 A.2.2 New Page A-4 A.2.3 Open A-4 A.2.4 Close A-4 A.2.5 Save A-4 A.2.6 Save As A-4 A.2.7 Import A-4 A.2.8 Print Setup A-5 A.2.9 Print A-5 A.2.10 Exit A-5 A.3 The Edit Menu A-5 A.3.1 Undo A-5 A.3.2 Redo A-5 A.3.3 Cut A-5 A.3.4 Copy A-5 A.3.5 Paste A-5 A.3.6 Clear A-5 A.3.7 Select All A-6 A.3.8 Copy URL A-6 A.3.9 Paste URL A-6 A.3.10 Find / Replace A-6 A.3.11 Find Next A-6 A.4 The Insert Menu A-6 A.4.1 Get Attributes A-6 A.4.2 Horizontal Rule A-6 A.4.3 Forced Line Break A-6 A.4.4 Image A-6 A.4.5 Image Map A-7 A.4.6 Link A-7 A.4.7 Anchor A-7 A.5 The Format Menu A-7 A.5.1 Remove Format A-7 Page iv 55 NaviPress and NaviServer Table Of Contents A.5.2 Special Style A-7 A.5.3 Heading A-8 A.5.4 Paragraph A-8 A.5.5 List A-9 A.5.6 Form A-9 A.5.7 Style Sheet A-9 A.6 The Tools Menu A-9 A.6.1 Show HTML A-9 A.6.2 NaviLinks A-9 A.6.3 Check Links A-10 A.6.4 Describe Page A-10 A.6.5 Search Server A-10 A.6.6 Server Administration A-10 A.6.7 General (Preferences) A- 10 A.6.8 Extensions/MIME (Preferences) A- 10 A.6.9 MIME Viewer (Preferences) A-l 1 A.6.10 Save As Filters (Preferences) A-l 1 A.6.11 MiniWeb Icons (Preferences) A-l 1 A.6.12 NaviServer (Preferences) A-l 1 A.6.13 Delete A-l l A.7 The Browse Menu A-l l A.7.1 Backward A-l l A.7.2 Forward A-l l A.7.3 Stop A-l l A.7.4 Reload Page A-12 A.7.5 Global History A-12 A.7.6 Hot List A-12 A.7.7 Add to Hot List A-12 A.8 Window Menu A-12 A.9 Help Menu A-12 APPENDIX B MiniWeb Window, Menus, and Icons B-l B. l NaviPress MiniWeb Window B-l B.l.l Toolbar B-2 B.1.2 Overview of Menus B-3 B.2 The File Menu B-3 NaviPress and NaviServer 56 Page v Table Of Contents B.2.1 New MiniWeb B-3 B.2.2 New Page B-3 B.2.3 Open B-4 B.2.4 Close B-4 B.2.5 Save B-4 B.2.6 Save As B^ B.2.7 Import B-4 B.2.8 Exit B-4 B.3 The Edit Menu B-4 B.3.1 Cut B-5 B.3.2 Copy B-5 B.3.3 Paste B-5 B.3.4 Clear B-5 B.3.5 Copy URL B-5 B.3.6 Paste URL B-5 B.3.7 Set Stationary B-5 B.4 The View Menu B-5 B.4.1 Clean Up B-5 B.4.2 Zoom In B-5 B.4.3 Zoom Out B-6 B.5 The Tools Menu B-6 B.5.1 Describe MiniWeb B-6 B.5.2 Search Server B-6 B.5.3 Server Administration B-6 B.5.4 General (Preferences) B-6 B.5.5 Extensions/MIME (Preferences) B-6 B.5.6 MIME Viewer (Preferences) B-7 B.5.7 Save As Filters (Preferences) B-7 B.5.8 MiniWeb Icons (Preferences) B-7 B.5.9 NaviServer (Preferences) B-7 B.5.10 Delete B-7 B.6 The Browse Menu B-7 B.6.1 Global History B-7 B.6.2 Hot List B-7 B.6.3 Add to Hot List B-8 B.7 Window Menu B-8 B.8 Help Menu B-8 Page vi 57 NaviPress and NaviServer Table Of Contents APPENDIX C Installation C-l C.l NaviPress Installation C-l C.l.l Macintosh Installation C-l C.1.2 MS Windows Installation C-l C.1.3 Sun Installation C-l C.2 Running NaviPress C-2 C.2.1 Name Servers C-2 C.2.2 Proxy Servers C-3 5.15.1 Copying Preferences C-3 C.3 NaviServer Installation C-3 NaviPress and NaviServer 58 Page vii Table Of Contents Page viii 59 NaviPress and NaviServer Preface P.I Introduction NaviSofts' combination of NaviPress and NaviServer forms a client-server application development system. This unique integrated system provides a application platform for creating content, managing information and developing applications on the Web. Our tools combine: • Integrated WYSIWYG authoring and browsing of Web pages without typing HTML tags or names of URLs • Seamless access to both local and remote Web pages, allowing remote authoring over the Internet • The "MiniWeb," to graphically visualize Webs and organize collections of pages • "NaviLinking" for easy translation of text into hypertext • An information architecture to keep track of assets that complements a hypertext- based navigation architecture • HTML as a general purpose forms-oriented interface to a DBMS that extends the reach of transaction processing applications to wide-area networks • Hierarchical access control, cost accounting, and version control of pages • Example "Blueprints" that function like Microsoft Wizards for the Web • Extensibility, to implement custom services P.2 Audience This manual assumes it's readers are familiar with the following: • The World Wide Web in general. • The basic concept of HyperText, and how it is used to navigate through information. Preface 60 Page P-l Legend • Browsing the World Wide Web. • The internet in general. • The use and management of your own computer system. This manual does not provide detailed information on any of the above topics. P.3 Legend The following text conventions are used throughout this manual: • Text in bold will be used for menus, menu items, and buttons. • Italics will be used for emphasis, filenames, and sometimes for d e name of a feature. For example, you might see the Page Window referenced. • Menu names and options will appear with arrows pointing from menu names to the option name within that menu. For example, the following would specify the Save option in the File menu: File->Save. This also applies to cascading menus. For example, the following specifies the Address option in the Paragraph submenu of the Format menu: Format->Paragraph->Address. • Example text will be shown in courier. For example, you might be asked to enter d e following text: http : / /navisof . com Page P-2 61 Preface CHAPTER 1 Introduction 1.1 About the Product Fueled by the immerging software and services that surround the World Wide Web, the Internet has recently experienced an explosive growth. Most software recently released for use with the Internet is either a cruiseware, commerce servers, or stand-alone hypertext markup language (HTML) editors. Lacking is an integrated system for creating content, managing information and developing applications on the Web. Focusing on the problem of creating and maintain an all encompassing Web-application, NaviPress and NaviServer, a client-server application, fills this void. Our software is intended for companies and enterprising individuals who want to create and maintain innovative, operation Web applications. The "developer" that NaviPress and NaviServer help best is the infopreneur, enterprising individuals or companies who are moving advertising, marketing, support, and sales activities to the Web. Today, developing an application that provides or collects information through the Web requires a variety of skills-knowledge of the hypertext transfer protocol (http), HTML, common gateway interface (CGI), Unix, and a programming in C or Perl. Cruiseware provides access to the Web once someone has put up the pages, commerce servers assure a secure channel of communication between client an server, and a stand-alone HTML editor produces a file of HTML output on the desktop. Despite all this software, the information provide still needs a programmer to put all the pieces together into an application. Greatly simplifying development of applications for the Web, the integrated NaviPress and NaviServer is as easy to use as a wordprocessor. This network publishing and extensible information system provides an interactive environment for building applications with a point-and-click interface. An applications developer can easily create Introduction 62 Page 1- 1 Documentation Structure and post artistic Web presentations, manage the assets, and process the information. NaviSoft is a new product category to the World Wide Web, one that focuses exclusively on making it easier to create and maintain Web applications. 1.2 Documentation Structure This manual will be set up like a tutorial. You should be able to follow along and do each example as they are explained. All examples and figures were done on a PC, and where differences apply to other platforms they will be mentioned. The following is a brief description of each chapter Page 1-2 63 Introduction CHAPTER 2 Browsing 2.1 Introduction This chapter provides a brief description of using NaviPress as a browser to browse the World Wide Web. Since authoring new web pages and browsing the Web are completely interconnected with NaviPress, this is an important first step. Before you begin, please make sure that NaviPress and NaviServer have been correctly installed on your system. Refer to accompanying installation guide for instructions. 2.2 Starting NaviPress Start up your copy of NaviPress. If you are using a PC or Macintosh, you will need to double click on the appropriate icon. If you are using a UNIX system, then type navipres at the prompt. This will bring up an empty web page in a Page Window, and a new MiniWeb, in a MiniWeb Window (die MiniWeb window will have the title MiniWeb at the top of the window). MiniWebs will be explained in greater detail in Chapter 4 "MiniWebs", and can be ignored for now. 2.3 Page Windows The empty web page is shown in a Page Window. This window is used for browsing the World Wide Web and looking at web pages (note that this window is also used for authoring and other functions of NaviPress which are covered in later chapters). Browsing 64 Page 2-1 Page Windows The following figure is an example of a Page Window with an empty web page in it: 2.3.1 Browsing To use the Page Window as a browser, simply enter the URL (name of the web page) you wish to look at in the Location Box. For example, to look at NaviSoft's home page, enter the following in the Location Box, and hit return: http : / /navisoft . com This Page Window should now show NaviSoft's home page. You may notice several thing while the page is loading. • The stop button is no longer grayed out (it has become active). This button may be pressed when it appears like Uiis to stop whatever function is being preformed. • A constantly building web (an animation) appears on the top right comer of the window. • The status bar at the bottom of the window shows a message relevant to the current state of the current action. • You may see a question mark appear at the top of the page, soon to be replaced by the Navisoft logo. This question mark appears while an image is being loaded, and will be replaced by the image when it is fully loaded (if you do not notice the question mark, then that means your system is fast enough that you don't see it). If you have set your preferences (see the Appendix C "Installation") so tiiat pictures are not loaded by default, then this question mark will always appear instead of the image. In this case, if you click die mouse on the question mark it will then replace it with the image. Page 2-2 65 Browsing Page Windows To jump to a new page that is linked to text (text with links is shown in blue, italics, and underlined) simply click the mouse on the appropriate text. Single clicking on the text replaces the page in the current Page Window with the new web page. Double clicking creates a new Page Window showing the new web page. For example, single click on the line in NaviSoft's Page that says What's New?. This replaces the current page with the What's New page. You should also notice, now, that the Back Button is no longer grayed out. Go ahead and click this button to take you back to the home page. Once back in the home page, you should notice that the Forward Button is no longer grayed out. This button will take you to a web page you have just gone back from. These two buttons can be used to traverse all the web pages you have visited in this § d Page Window. The forward and backward functions are also available in the Browse menu. You should notice that the What's New line is now green instead of blue, and die underline is now dashed. Green text means that the page diat this link points to is cached (stored in local memory). This makes it much faster to use that link again, because the page no longer has to be fetched across the internet. Now, click on the down arrow to the right of the Location box, you will get a list of all web pages that have been viewed in that Page Window. In this case there should be three items in the list; NaviSoft's page, the What's New page, and your original empty page. Any page in this list may be viewed by selecting it from the list. A similar list of all the web pages viewed by any Page Window this session is available through the menu item Browse->Global History. 2.3.2 Extras Here are some extra browsing features that you may find useful. 23.2.1 Reloading Page If for some reason you need to reload the current page you are viewing in the Page Window (either because you think the original page has changed, or your copy has become corrupted) you may use the menu item Browse->Reload Page. 2.3 L2 Hot List NaviPress also allows you to keep a Hot List from session to session. This is a list of web sites (URLs) that you think you might visit frequentiy, or that you just want to remember and have easy access to. For example, if you want to put the Navisoft home page in the Hot List, then go to that page in the Page Window (enter the URL in the Location Box, or if you have visited it already choose it from the list attached to the Location Box, see sections above for more information). Choose the menu item Browse->Add To Hot List. The page is now added to die list. To see the list, choose the menu item Browse->Hot List. This will invoke the following window: Browsing 66 Page 2-3 Exiting NaviPress Double clicking on any entry in the list will bring up that page in the Page Window. The following are descriptions of the buttons in this window: Fetch causes the selected page to be displayed in die Page Window. Close closes the Hot List Window. Add Label allows you to add a label above a selection in the list. Add Separator adds a line across die list above the selected item. Move Up moves the selection up die list. Move Down moves the selection down the list. Remove removes the selection from the list. Copy URL copies the URL of the selection. Help invokes the help window on die Hot List. Note that this list is stored in your NaviPress preference file (navipres. prf). Deleting this file will erase your list. 2.4 Exiting NaviPress To exit NaviPress, choose the menu item File->Exit. Every time NaviPress is started, a new MiniWeb directory is created (MW1, MW2, etc.). If you have not saved anything into this directory, then you will be prompted with the Page 2-4 67 Browsing Exiting NaviPress following dialog when you exit: You may delete this directory if you wish. Browsing 68 Page 2-5 Exiting NaviPress Page 2-6 69 Browsing CHAPTER S Authoring 3.1 Introduction This chapter explains the basic techniques in creating your own web page. It assumes you are already familiar with browsing, and associated features (see Chapter 2 "Browsing"). NaviPress allows you to create web pages with the ease of a word processor. Web pages are written in the language HTML, and are normally written with a simple text editor. NaviPress allows you to see the web page you are creating as you are creating it. NaviPress also allows networked authoring. This means that you can browse the web while creating a page, and import information over the web that you would like to incorporate into your page. You can also use links created in your page as soon as you create them. The page you are creating is a fully functional web page right from the start. It is suggested that you save your file after ever step listed below. 3.2 Creating a Web Page Start up NaviPress. The Page Window comes up widi a blank page in it. To create your own web page, you start by editing diis blank page. First, save the page to a new name. Choose the menu item File->Save. Since this is a new page that hasn't been saved yet, this invokes the following Save As dialog (if me page has been previously saved, then choosing File->Save will simply save the most recent version without invoking a dialog): Authoring 70 Page 3-1 Simple Editing Change the name of the file from pagel.htm to offices.htm, then click Save. This saves your page under the new name. You may notice that your file is in a new MiniWeb directory (e.g. MW1). A new MiniWeb directory is created every time you start NaviPress, and is the default starting directory for saving pages you author. The MiniWeb will be discussed in greater detail in Chapter 4 "MiniWebs". 3.2.1 Titling Your Page You now have a saved new page. This example will walk you through creating a page that can later be used as part of a customer support web site for you or your business. This page will contain a list of locations of your offices around the U.S. The first thing to do is to title tiiis page. In the Title Box, change the title to U.S. Sales Offices. As soon as the focus leaves the Title Box, you should notice that the web icon to the left of the Location Box has now changed. This means that unsaved changes have been made to the page. Saving the page will change this icon back. 3.3 Simple Editing This section will go tiirough some simple editing features. In the main body of die Window Page, type the following text: This is a test sentence . This sentence can be edited with d e mouse and edit keys as with most word processors. Go ahead and make a few changes to this sentence to see how it works. 33.1 Formats Text may also be formatted with a number of formats available under the Format menu. Page 3-2 71 Authoring Simple Editing 33.1.1 Special Styles Select the word test, then choose the menu item Format->Special Style->Bold. This will change the word to be bold faced. If you look in the menu again, you should notice that die menu item Bold has a mark by it to indicate that it applies to the selected text. To remove the bold format, choose the same menu entry again. The other styles in the Special Style menu can be used in the same way to format text. Go ahead and try out the different formats to see how they change the text. 3.3.1.2 Headings The Format->Headings menu allows you to turn text lines into preformatted headings. There are six different heading types. Select the entire line of text you have typed in, then choose the menu item Format->Headings->Hdg 1. This will turn your line into a Heading 1 format. To remove the format, select the entire line of text, and then choose the menu item Foπnat->Remove Heading Format. The other heading formats can be used in die same way. 3.3.1.3 Lists This is another type of formatting that allows you to create one of three different types of lists. Unnumbered lists are indented widi bullets (dots) placed in front of them. Type in several lines of sample text, select the text then choose the menu item Format->Lists->Unnumbererd List. This will turn your text into an unnumbered list. To remove the list format, select the text in the list and choose the menu item Format->Remove List Format. Numbered lists are similar to unnumbered lists, except mat sequential numbers are placed in front of the lines in the list. Definition lists are used to pair off alternating lines. The entire list will be indented, with every other line being indented a little further. This list is used if you have a list of terms followed by a definition of each item. For example: Alaska No offices in this state. California Two offices in this state Utah No of fices in this state . In this next example, each state name would be a Term and each following line would be a Definition. A term line may be forced to a definition line by choosing the menu item Format->Lists->Definition. and vica versa. Authoring 72 Page 3-3 importing Graphics 3.3.1.4 Format Borders Choosing the menu item Format->Show Border will show dotted lines across your page between each group of text with a Form or List format. These lines are only the borders and can not be edited in any way. Format->Hide Border will remove the borders. When you are finished experimenting, delete any text and formats you have in the window before continuing. 3.4 Importing Graphics Graphics may easily be imported across the internet. Choose the menu item Elements->Image. The following dialog will be invoked: Location: OK Cancel Alignment DIMfSC_» O Top O Middle <S> Bottom Help If you know the URL for the graphic you wish to import you can just type in into the Location Box in this dialog. If you don't know the URL and the graphic is on a NaviServer, or is on your local file system, then you can use the Browse button to find it. Click Browse. The following dialog will be invoked: First you must choose a NaviServer to search on. You can either enter one in the Location Box at the top of the dialog, or you can choose one from the Drivers/Servers/MiniWebs list Page 3-4 73 Authoring Adding to the Page that appear when you click on the arrow to the right of the bottom of the box. This is a list of all the NaviServers you have ever visited in any session. If you have already gone through the example in Chapter 2 "Browsing", then NaviSoft's NaviServer will be in the list. If not you will have to type it in. Type or choose: http://navisoft.com/ The Location Box at the top of this dialog should now show: http : / /navisof . com/ This is the directory you are currently browsing. Below this is a list of directories (on the left) and a list of files in the current directory (on the right). Scroll down the Directory list until you see test, then double click on test. Scroll down the new directory list until you see support, then double click on it. The File list should now contain a bunch of. gif files. Select custsupp.gif fτom the list and then click Insert. This will return you to the original image dialog. There are three radio buttons in this dialog, Top, Middle, and Bottom. These allow you set which part of the graphic will be aligned with the text. Select Top, then click OK. 3.5 Adding to the Page Below the image type the following (don't forget to hit RETURN after importing the picture): Office Locations and then below that import the following two graphics in order: http : / /navisoft . co / est /support /line . gif http: / /navisoft . co / test /suppor /surf . gif You are now going to change the surf image. Select the image (by dragging the mouse over it, exacdy like selecting text, or by double clicking on it). Then choose the menu item Elements->Get Attribute. This will invoke the Image dialog widi the image's URL in the Location Box. This menu item is very useful. When ever Get Attribute is chosen, it will invoke the appropriate dialog for whatever the selection is, in this case an image. Change the image name to: http : / /navisoft . com/ tes / support /usmap . gif This should import the following image: Authoring 74 Page 3-5 Adding to the Page Below this image type the following Your Company's U.S. Sales Offices If you would like information about our products or services, see our online catalog, contact us through the help desk, or call the nearest regional sales office Use the map to find the office closest to you or call: 1-800-555-5555 International Sales Offices Then import another line graphic. Note that to get single spaces between lines, use SHIFT- RETURN. Now select the line: Your Company' s U. S . Sales Offices and then choose the menu item Format->Heading->Hdg 2. You now have the beginnings of a usable web page. 3.5.1 Copying Text from Other Pages Now you will need to add a list of all 50 states to the bottom of your web page Since you probably don't want to type out all fifty states, you will use a short cut. This will show you how to use the browsing functions of NaviPress to help you create your own page Choose the menu item File->Open This will open a file browsing dialog (similar to the Page 3-6 75 Authoring Adding to the Page image dialog). In the Location box at the top of this dialog, enter the following URL (or use the server and directory lists): http://navisoft.com/test/support/statelist.htm This will invoke a Page Window showing a list of states (not quite all 50, but close enough for now). Select the entire list with the mouse (and easy way to do this is to position the cursor at the start of the list, and then SHIFT-click on the end of the list). Next, click on die Copy icon. aa-' Return to your web page, position the cursor at the end of the page, and click on the Paste £-&.--. icon. The fifty states should now appear at the bottom of your page. 3.5.2 Creating Links You will now create a hypertext link in your page. Select the following line of text near the top of your page: International Sales Of fices Now choose the menu item Elements->Link. This will invoke the following dialog: This allows you to enter an URL to link to the selected text. You can either enter the URL in the Link To Page Box at the top of the dialog, or you can click Browse to invoke a Browse dialog which works just like the Browse Image dialog (see section 3.4 "Importing Graphics" on page 3-4). The Append Anchor Name Box at the bottom allows you to link to specific anchors within a page. Anchors will be discussed in the next section. Enter the following URL and click OK: http : / /navisof t . com/ test /support/ dist_lis .htm The text is now linked to this page. You can test this by clicking on the text and jumping to die new page. 3.5.3 Creating Anchors You will now create anchors in the text and then link the map of the U.S. to those anchors. Authoring 76 Page 3-7 Adding to the Page We will use two states for an example. Select the text Kansas and then choose the menu item Elements->Anchor. This will invoke the Anchor dialog. This allows you to enter an anchor name for the selected text. An anchor name is just an arbitrary reference for that piece of text so you can later create a link to it. Enter Kansas as the anchor name (this makes it easy to remember, but it does not need to be the same as the selected text). You should notice that Kansas is now magenta. This means that it has an anchor associated with it. If you want to see the anchor associated with a piece of text, select the text and choose the menu item Elements->Anchor, or Elements->Get Attributes. Go ahead and do tiiis with Kansas to see how it works. You can then either delete, change, or keep the anchor from this dialog. Now create another anchor for Wyoming the same way you did for Kansas (except, of course, you should name it Wyoming instead of Kansas). Make sure you save your page at this point. 3.5.4 Image Maps You will now create an image map from the U.S. map. An image map is a table that is assocaited with a graphic that has "hot spots", or areas that have links to either anchors or other pages. Select the U.S. map graphic at the top of your page. Then choose the menu item Elements->Image Map. This will invoke the following dialog: Map Name: Create Rectangle: Rectangle List: Location: IΞ Selection Type:' O Default File Location On the left side of die dialog is a small box labeled Create Rectangle. This window has a scrollable copy of your image in it. To create a hot spot in the map, scroll to the region you want active, then use the mouse to drag out a rectangle. To do this, position die mouse over one comer of where you want the rectangle to be, and tiien press the mouse button. A dragable rectangle will appear. Release the mouse button when you have dragged out the desired rectangle. For this example, scroll through the map until you can see the map of Kansas in the window, then drag out a rectangle trying to fill as much of Kansas as you can. Page 3-8 77 Authoring Style Sheets The Location Box, under the Create Rectangle box, is where you enter the URL you wish to link this rectangle to. You can either enter the URL or click Browse to invoke a Browse dialog. Since you are going to create a link to an internal anchor, you do not need to enter the full URL for your page. Simply enter the filename followed by #Kansas. For example: offices.htm#Kansas If you enter partial pathnames or just file names, they are taken to be relative to the current page. So this will link the rectangle to the anchor Kansas in your page. Now click Add. This will add a description of die link to the Rectangle List Box to the right of your image in the dialog. Repeat the steps above to create a link to Wyoming. You should now have two rectangles listed in the Rectangle List Box. Click OK. You may want to save your page at this point. You have now created links to the anchors in your page. To use the links, click on the appropriate part of the map (e.g. click on the map of Kansas to jump to the Kansas entry in your list). 3.5.5 Copying URLs This section explains how to easily copy the URL from an open web page. At the bottom the page you are creating, add the following text: Copyright © 1995, YourCompanyName, Inc. You are now going to link this text to a page by first finding die page and looking at it, then copying the URL from that page. Choose the menu item File->Open, and open the following web page: http://navisoft.co /test/support/copyrigh.htm You should now have two pages open, the page you are creating and the copyright page. Go to the copyright page and select the menu item Edit->Copy URL. This is like a normal copy, except it copies the URL from the page. Now return to your page and select the text you just typed in at d e bottom. Then choose the menu item Edit->Paste URL. The text is now linked to die copyright page. Test the links by clicking on the linked text and following the link to the copyright page. 3.6 Style Sheets Style sheets allow you to change the way Headings, Paragraphs, and Lists that are displayed (all under the Format menu). A style sheet is linked to a specific page, and allows you to change the styles for this page. Note, however, that only NaviPress browsers will be see the new styles. All other browsers will ignore the style sheet, and use their own Authoring 78 Page 3-9 An Example Page default display settings. Every copy of NaviPress has a default style sheet associated with it. Each user can also have their own personal style sheet that will only affect how they see the formats when using NaviPress. Style sheets are created and edited using the menu item Format->Style Sheet. 3.7 An Example Page If you would like to see and example of a page similar to the one you have just created, browse the following page: http://navisoft.com/test/support/ hereis.htm 3.8 Publishing Your Page Once you have finished creating your web page and are happy with it, you can publish it to a server. Right now your page only exists on your local disk; although you can browse your web page, no one else can. To enable other people on the internet to look at your web page you will need to publish it to a server. Choose the menu item File->Save As. You now need to choose a NaviServer to publish your page to (you must have write permission for the location you want to publish). If you have ever visited die NaviServer you are interested in, it will show up in the list at the bottom of the dialog. To see the list, click on the down arrow to the right of the box at the bottom of the dialog. If this is a NaviServer you haven't visited yet, tiien you will need to type in its URL in the Page Location Box at the top of the dialog. Note tiiat this NaviServer may be any server on the internet that you have write permission to, although it is more common to publish to your own NaviServer. Once you have chosen a NaviServer and filename, click Save. You have now published your page. Page 3- 10 79 Authoring CHAPTER 4 MiniWebs This chapter is divided into three main parts. The first part is a brief introduction. The next part is a tutorial that takes you through examples of the important features of MiniWebs. The last section gives an overview of the features of MiniWebs. This last section is useful as a reference and may be referred to during the tutorial for further explanation. 4.1 Introduction MiniWebs are a unique feature of NaviPress. In the simplistic view, a MiniWeb is a graphical representation (the MiniWeb Window) of a special directory containing web pages and other web related files. It is rare to want to author a single web page. More often you would create a web project, or a group of related web files. MiniWebs provide many useful features that greatly facilitate the authoring of web pages based projects. You may have noticed by now that when authoring with NaviPress you are, by default, working within the context of a MiniWeb. When you start up NaviPress, an empty Page Window comes up, as well as a new MiniWeb window. All of the files that are physically in the MiniWeb directory appear as icons in the MiniWeb Window. Also, all the files that these files have links to appear in the MiniWeb, even if they are not physically located in the MiniWeb directory. MiniWebs 80 Page 4-1 Introduction The following is an example of a MiniWeb Window: 4.1.1 Terminology The following terms are used throughout this chapter: relative link This mean that the link is relative to the location of the page the link is in. For example, if the page http://garage.com/sofa/sofa has a rela¬ tive link to http://garage.com sofa/spam, then when this link is acti¬ vated it will look for a file named spam in the same directory. So if you copy this page, but not the file spam, then the link to spam will no longer work. absolute link This means that the link is to an specific URL. For example, if the page http://garage.com/sofa/sofa has an absolute link to http://garage.com sofa/spam, then when tiiis link is activated it will look for http://garage.com/sofa spam regardless of where the original page is. inlined This refers to a separate file that is incorporated into the middle of a web page. Currently, only graphics may be inlined. However, note that even though only graphic files can be inlined, not all graphics files have to be inlined. ghost files These are files that are visually represented in the MiniWeb but aren't physically in the web. Their icons are light gray in color, and can have either light gray text or green text underneath the icon. home page The home page is shown in the Home Page Box at the top of the MiniWeb, and is considered to be the main page of the MiniWeb (usually the starting page). Page 4-2 81 MiniWebs Tutorial 4.1.2 MiniWeb Icons The following is a list of the icons appearing in the MiniWeb: • web pages image files image map files sound files video files style sheet files fil aes of unknown type 4.2 Tutorial This section takes you through actual examples of working with a MiniWeb. In the previous chapter you learned how to autiior and publish a page. The page you made was part of a hypothetical customer support MiniWeb you were constructing. This example will take you through the rest of the steps of creating the full blueprints for a customer support web. Blueprints are ready made web pages mat you simply edit to fit your specific needs. This saves you the time of creating webs and pages from scratch. 4.2.1 Copying the MiniWeb The first step is to copy the main body of d e customer support MiniWeb. Open the following MiniWeb: http : / /navisoft . co / test /examplel MiniWebs 82 Page 4-3 Tutorial In the MiniWeb window, choose the menu item File->Save As. Enter the location you want to put the MiniWeb in the Location box, and click Save. This will create a new MiniWeb directory and copy all the files in the open MiniWeb into it. You now have your own copy of the customer support MiniWeb. 4.2.2 Adding Your Page You will want to add the office location page you authored in die previous examples to the support MiniWeb. Open your page, ofβces.htm, so that you now have your page loaded in a Page Window, and your version of the customer support MiniWeb open in a MiniWeb window. In the Page Window, choose die menu item Edit->Copy URL of Page. Then go to the MiniWeb window and choose the menu item Edit->Paste URL. The following dialog box will be invoked: Make sure that Relative is selected from the Save Pictures options, and then click OK. This will copy your file into the MiniWeb, as well as all die inlined images in it. You should see an icon representing your file appear. You will notice that your icon now points to several other icons. Most of these icons will be ghost icons (see section 4.1.1 "Terminology" on page 4-2), except for the image maps, which will be solid. This is because the links you created in your page point to die original MiniWeb, and not die copied version you are working with now. It is necessary to fix these links (a bit of a task). 4.2.2.1 Fixing the Images First, go through and select all of your images, and then choose the menu item EIements->Image. You can then edit the URL for the images. Since all the file names will be the same, all you need to do is die delete die first part of the URL to make it a local reference. This will point it at the local copy. Note that when you do diis you will lose your image map. The image map will still be there, but since you changed die image, the link to the map is lost. This is easily fixed. Page 4-4 83 MiniWebs Tutorial Select the map of the states and choose die menu item Elements->Image Map. A dialog will be invoked asking you want to read in the existing file. Click Yes. This will load your image map. Simply click OK in the image map dialog, and it is reconnected. 4.2.2.2 Fixing the Page Links Next you need to fix all the links to the pages in the MiniWeb. Go through your page and select all of your linked text (holding down CONTROL allows you to click on linked text without jumping to the link, which is useful for selecting linked text), then choose the Elements->Link menu. You may find it helpful to click Select Only in this dialog. This button will make it so that only the exact text with the link is selected, which can sometimes help you avoid problems. Change the URLs in this dialog just like you did for the images. Delete d e first part of the name, so only the filename remains, making the links relative to the local copies. 4.2.23 Linking to the Home Page The final step is to link your page into the home page of the MiniWeb, support.htm. Find the icon for support.htm in the MiniWeb and double click on it. You should see some linked text in the middle, one line of which reads: Of fice Locations This text currently links to die page whereis.htm, the prototype for the page you created. Change tiiis link to point to your page, qffices.htm. You have now fully integrated your page into the MiniWeb. You can now delete die page whereis.htm. To delete it, select the icon, and either press Delete, Backspace, or choose the menu item Edit->Cut. 4.2.3 Merging MiniWebs Your support MiniWeb is still not quite complete. There is another MiniWeb that contains a few pages that you will need. You will now open this MiniWeb and merge it into your main support web. Choose the menu item File->Open, and open the following MiniWeb: http: / /navisoft . com/ test/example2 This MiniWeb contains three actual pages, and the rest of the icons are ghosts. These ghosts are relative links to pages that don't exist in this MiniWeb yet, but do exist in die support MiniWeb that you copied over previously. These ghosts will be updated to point to correct files automatically when you copy die solid icons over. Drag and drop d e icon forum.htm from the new MiniWeb to your support MiniWeb, this will copy the file into the support MiniWeb. All the links should now go to the correct files, except that you will now have two new ghost images in your support web. These are from the other two files in the new MiniWeb thatforum.htm linked to. Since these are relative links, dragging and dropping the otiier two files into the support MiniWeb should MiniWebs 84 Page 4-5 Feature Overview fill in these ghost icons. So, now repeat the process for the other two files, news.htm and mail.htm. All of the links coining off forum.htm should now be to solid icons. The last step is to add a link from the support web's home page to forum.htm. Open support.htm. In the middle of me page is a list of linked text. In the middle of this list is an unlinked line: Discussion Groups and FAQs Link this line to forumZhtm, using the Elements->Link menu item. You have now completely merged die new MiniWeb into your main support web. Don't forget to save your changes. 4.3 Feature Overview This sections gives an overview of MiniWeb features. Arrows between icons represent links between the files. Icons can be dragged and dropped into otiier MiniWeb Windows and into Page Windows. Links in a Page Window can be dragged and dropped into MiniWeb windows. Single clicking on an icon will select that icon. 43.1 Color Coding MiniWebs are color coded to show the status and relationships of the files in the MiniWeb. The following are lists of the colors and their meanings. 4.3.1.1 Icon Color Solid The file is physically located in the MiniWeb. Dithered The file is a relative link, but is not physically located in die Mini¬ Web. Green text The file is an absolute link and is not physically located in die Mini¬ Web. Broken The file is physically located in die MiniWeb but has unsaved changes. 43.1.2 Link Color Blue arrow Link to an inlined image. Green arrow Link from a form to where that form will be submitted. Cyan arrow Both files are linked to each other. Gray dotted A link that doesn't actually appear in the page when it is displayed. Black arrow All other links. Page 4-6 gj MiniWebs Feature Overview 43.2 Double Clicking on Icons Double clicking on an icon will attempt to preform the appropriate action. The following is brief explanation for the effects of double clicking on various icons: Page If the page exists in the MiniWeb, or is an absolute link, it will be opened in a new Page Window. If the page is a relative link and doesn't exist in the MiniWeb (light icon) then you will asked if you want to create it. Video An attempt will be made to launch an external viewer. If no viewer is available, you will asked if you want to save the file. Sound An attempt will be made to launch an external player. If no player is available, you will be asked if you want to save the file. Graphic An attempt will be made to launch an external viewer. If no viewer is available, and the image is either a GIF, JPEG, or XBM, then a new page will be opened containing just the image. Otherwise you will be asked if you want to save the file. Image Map The Image Map dialog is invoked. 4.33 Drag and Drop Features The MiniWeb allows you a range of features based on the drag and drop principle. Dragging and dropping icons from one MiniWeb into another, copies that file into the second MiniWeb. Dragging and dropping icons from a MiniWeb into a Page Window is equivalent to opening the file associated widi that icon from the Page Window (except that a new Page Window won't be created in this case, the icon is opened into die Page Window it is dropped into). You can also drag and drop links from a Page Window into a MiniWeb. If you click on the linked text, and tiien drag and drop tiiat into a MiniWeb, it will copy the file the link points to into the MiniWeb. 43.4 Filling in Relative Links When you have a relative link in the MiniWeb, but the file does not actually exist in the MiniWeb, then the icon for that file is light gray. It is an easy matter to "fill in" this file if it exists elsewhere. Any method used for copying the file into the MiniWeb (dragging icons, copying URLs, Save As, etc.) will add die file to die MiniWeb, and fill in the icon to show the change. This is useful when you are copying several related files from elsewhere. Copying the first file adds diat file and die relative links. Then as you copy the other files, the links are filled in. MiniWebs 86 Page 4-7 Ediung With MiniWebs 4.4 Editing With MiniWebs There are a range of useful editing related features with MiniWebs (mostly available under the Edit menu). 4.4.1 Copying URLs There are several ways the menu item Edit->Copy URL works with MiniWebs. It is important to note that if no icon is selected in a MiniWeb and Edit->Copy URL is chosen, then the URL from the MiniWeb is copied. If an icon is selected, then the URL for that icon will be copied. If an URL is pasted from a MiniWeb into a Page Window, it will automatically add a link in the page to tiiat URL. If the URL is pasted over selected text, then the link will be associated with that text. If no text is selected, then die title of the page that was copied will be inserted as text into the page, and that text will be linked to the copied URL. If the URL from a Page Window is copied and then pasted into a MiniWeb, then that page will be added to the MiniWeb. 4.4.2 Deleting Icons There are several ways to delete icons. Selecting an icon and either pressing Delete, Backspace, or choosing the menu item Edit->Cut will remove the icon. Note that when an icon is removed any ghost files that it points to that aren't pointed to by any other icon are also removed. Also note that if another page has a link to the deleted page, a ghost icon will remain. 4.43 Saving When you save a MiniWeb it will also save all files in the MiniWeb that are open and have unsaved changes. 4.4.4 Setting the Home Page To set a new home page for a MiniWeb, click on the arrow to the right of the Home Page Box at the top of the MiniWeb. This will give you a list of all die pages in the MiniWeb. Selecting a page from this list will set it as the home page. 4.4.5 MiniWeb Button The MiniWeb icon on the upper left of the Page Window can be clicked on to bring up the MiniWeb Window for that page (if it exists). Page 4-8 87 MiniWebs CHAPTERS The NaviServer 5.1 Introduction NaviServer allows you to save pages and MiniWebs from NaviPress to the server. It automatically indexes the full text of any pages, does version control, includes powerful permission and cost models, and has special features like NaviLinking. NaviServer is fast. Instead of forking on every connection, the NaviServer uses asynchronous socket I/O and continuations to maximize use of bandwidth. NaviServer is DBMS-centric. Unlike some database integration packages that you just append, the NaviServer gives fast access to data. You can search existing data, enter new data and update old data. You can even define new database tables with a simple HTML forms based interface. 5.2 Quick Start See Appendix C "Installation", for installation directions. This section gives instructions on starting up NaviServer. In the examples, text enclosed in o is meant to be substituted widi the information described. Set the environment variable NS_HOME to the NaviServer directory. # setenv NS_HOME <ns directory> Before running NaviServer, you need to start die database. Type the following: % $NS_HOME/bin/nsstartdb The NaviServer 88 Page 5-1 Quick Start To start a server in the foreground, type: % $NS_HOME/bin/nsd - f To start a server in the background on port 80, log in as root and type: # $NS_HOME/bin/nsd -u <user who owns NS_HOME> 5.2.1 Command-line Options The following is a list of command line options available when starting up the NaviServer. Text in courier after the option is meant to be substituted as described in the options explanation. accounting mode archive versioning mode verbose mode run in the foreground enroot to the page root at startup access log (default: no log file generated) error log (default: for root, /usr/adm/nsd-port#.log, other users, /tmp/nsd-port#. log) use port number port (default: for root, 80) set uid to uid at startup set uid to tiiat of useruser at startup set NS_HOME directory todir (default: /usr/local/n§ set directory GET file name tof ile (default: index. html) set map directory for -users todir set pages directory todir (default: NS_HOME/pαges) x set CGI prefix to prefix (default: None, disabling CGI's) set directory of CGI scripts todir (default: NS_HOME/cgϊ) set database server toserv (default: ns) set database name todb (default: ns) set database user touser (default: nsadmin) set database password to pass (default: none) set server hostname tohost (default: fully qualified IP hostname) set server location toloc (default: http://hostnαme:po f set poll timeout totime seconds (default: 60) 5.2.2 rclocal The $NS_HOME/bin/rc.nsd is an example script that contains all the information you need to run at startup. Note that this script is not available for all systems. If you put it into your file rc.locαl, the NaviServer should come up on port 80 when you boot the machine. Page 5-2 89 The NaviServer Searching the NaviServer 5_3 Searching the NaviServer The NaviServer automatically generates HTML forms that can be used to search the following: • NaviServer system tables (e.g., ns_permissions, ns_users) • User-defined tables (e.g., customer feedback, inventory) • The full-text of all the pages stored on the server • Metadata that describes either local or remote pages To get an HTML page with links to most of the server search forms, choose NaviPress 's menu item Tools->Search Server. 5.3.1 Searching Database Tables When the server processes a filled out SearchForm, it translates the form data into an SQL query and displays die results in a table (either PRE formatted or HTML3 table format). 5.3.1.1 The Body of the Search Form The search form contains one line for each column in the table. The first part of the line is a check box. If checked, the value of that column is returned upon form submission. The second part of the line is the name of the column. You select the comparison operation from the third element: a SELECT box. The operators in the box vary according to the type of the column. Number types, such as integer and float, have the following operators: = , > , < , >= , <= , <> , is null , is not null The text types (char, text, and varchar) allow the following: =, <>, contains, like, not like, is null, is not null The text operators are case-sensitive. The like operator lets you put a% character into the string that will match any substring. For example, Jo% Smith will match John Smith, Joe Smith, and Joseph Smith, but not Frank Smith. The contains operator is similar to the like operator, but puts a % character on either side of die value for you. So lemur is contained by stories about lemurs in Des Moines. The doc type (used for indexing die full text of a page) has die following operators: similar, boolean, is null , is not null The similar operator will try to find documents that are similar in content to what you type. The boolean operator lets you type in and's and or's between search key words. The NaviServer 90 Page 5-3 Searching the NaviServer The fourth element in the line lets you fill in or select a value for comparison in the database. 53.1.2 More on the Search Form At the bottom of the form is a set of widgets. You can select one or more columns to order the search results. You can also choose to eliminate duplicate rows by checking the appropriate box. Since some searches can return an extremely large number of rows, you can control the maximum number of rows to return. If you do not change anything on the form and just clicks Search, the server will return all rows and columns (up to the maximum to return) in the table. To bring the form back to its original state, you may click Clear All. Finally, you must click Search to send die form contents to the server and execute the search. 53.2 Searching for Pages 53.2.1 Searching the ns_default_collection All the pages of the NaviServer (as well as any remote pages that have been indexed) are indexed in the ns_default_collection table. Table ns_default_collection has the following columns: • ns_url: URL of the page • ns_title: title of the page • ns_body: full text of the page 5.3.2.2 Searching Medadata Tables Metadata tables are tables that have a column named ns_url and contain data describing the contents of that URL such as the author, the organization, or a quantitative rating of the page. Metadata table Search Forms contain an extra line that can be used to search the full text of the URL. 533 Hitlists and Hittables The NaviServer can display search results as a PRE-formatted table or as an HTML 3.0 table, if the browser can support diem (Netscape 1.1, NCSA Mosaic 2.5, or Arena). If the table is not a view (e.g. the ns_total_charges view), then the first column of the table contains values that are links to the Update Form for mat row. Values that are too long to fit in the table are truncated and shown ending in a *. The rest of the table's columns correspond to selected columns from the table. Values in the ns_url column are hot. If the user did a full text search, then these are links to the highlighted versions of the page (see section 5.3.4 "Highlighting and More Like This" on page 5-5). Otherwise, they are links directly to the page. Page 5-4 The NaviServer Entering Data and Updating It 53.4 Highlighting and More Like This 5.3.4.1 Highlighting The highlighting page contains all the text of the original page and marks any query terms as STRONG. The first term is marked as a named anchor and when a user traverses a link to a highlighted page, the browser will scroll directly to that first term. To determine which words to highlight, the server compares the roots of terms in the query with the words in the document. Some simple changes will not be matched, such as person to people and oasis to oases. At the bottom of the highlighted page the server inserts two links. The first is a link to the original page, which is more appropriate for editing. The second submits a query to the NaviServer for more documents like this one. 53.4.2 More Like This The server breaks a document into root terms and constructs a full text search. The NaviServer returns a Hitlist, just like that created from a Search Form. 5.4 Entering Data and Updating It Entry forms and Update forms let the user add and maintain data in the database. This applies to system data (such as the ns_permissions table) as well as any user-defined tables. Entering data is as simple as typing in (or selecting) the values you want and clicking Enter Data. The Clear Fields button resets the form to the original values. Columns of type boolean only allow values t (true), f (false), or NULL (no value, different than false). Entry and Update forms show these columns as radio buttons widi labels True, False, and Unknown. 5.4.1 Typechecking Each column in a table has a type. That type restricts the values that can be inserted. For example, columns of type integer can only store integers and date columns can store only dates in a particular format. Before inserting any data into die database, the NaviServer checks to make sure that any values conform to these restrictions. If any do not, the NaviServer returns a helpful error message, for example: Value "old* in column age is not of type integer 5.4.2 Dates and Times All Search, Entry, and Update (and Search) forms have special widgets for entering dates and times so users need not enter them in SQL format. To enter a date or time, users must select the radio button next to the date; otherwise, the NaviServer inserts a NULL or selects all rows. The default date and time values are the current date and time. The timestαmp type is a composite of both date and time. The NaviServer 92 Page 5-5 Creating and Deleting Tables 5.5 Creating and Deleting Tables To delete or add a table, choose the menu item Tools->Server Administration->General, and enter the URL for your NaviServer. This will open the NaviServer Administration page. To delete a table, click on Drop Table, under die Tables heading. This will bring up the Drop Table page. Enter the name of the table you want to delete and click Drop. To add a table, click on Add New Table, under the Tables heading. This will bring up the Add New Table page. The beginning of the page lists brief instructions on filling in the form. The actual table form is below this section. The first section to fill out in the table form contains general information about the table. This includes the table name, a description of the table, and a check box to determine if the table is searchable. Table Name This field can only contain one word composed of letters, numbers, and underscores. No other characters are allowed. Also, the table name can not be the same as any other table name, or one of the following reserved words: Page 5-6 93 The NaviServer Creating and Deleting Tables Table Description This field has no character restrictions, and should contain a meaningful description of the table. Table is Searchable This check box determines whether or not you will see a link to the table in the Search Server page. You would turn this option off if you didn't want users to have easy access to your table. The next sections contain column descriptions. You fill in the clumns you want, and any empty column descriptions at the bottom are removed. You can have up to ten columns. For each column, you will need to enter it's name, type, description, and select whetiier you want the column to be not null, unique, and indexed. Name This field contains the column name, and has die same restrictions as the table name (see above), except that it can not have the same name as another column in this table. Note that when choosing column names, it is a good idea to preceed each name in a given table wid an identifier that is unique from table to table. For example, if you were creating a problem report table, you might have problem_ in front of each column name. This will save you from running into possible problems later. Type This field contains die type of information that will be entered into this column. Choose one of the following values: text All characters are allowed. integer Any integer is allowed. real Any real number is allowed. boolean Only two values (true or false) are allowed. date A date. time A time. timestamp A date and a time. Description This field has no character restrictions and should contain a meaningful description of the clumn. not null If this box is checked, then this column must contain data. This means that if you are trying to add an entry to the table and this column is empty, then the table entry will be refused. The NaviServer 94 Page 5-7 Customizing NaviServer Forms unique If this box is checked then every entry in this column must be unique (i.e. different ti en every other entry). index If this box is checked, then tiiis clumn will be indexed. An indexed column can be faster to search than a non-indexed column. However, indexing columns slows down table updates, inserting new data into the table, and deleting data from the table. In general, you should only index the columns you think will be used most often when searching tables. For example, if you had a table of customer names and addresses, you would usually search the table by the customer's name. In this case it would make sense to index die column containing the customer's name. Note that indexing does not help you widi columns that contain long strings of arbitrary text, or when the column will be searched using the like or contains operators (see section 5.3 "Searching the NaviServer" on page 5-3). When you have filled in all the clumns you want, go to die bottom of the column sections and click Create Table. If you have entered any illegal characters for the table name, or the names of any of the columns, the names will be changed to make them legal. All spaces in names will be turned into underscores, and any other illegal characters will be removed. If the name is a duplication, or one of the reserved words, then a number will be appended to the end of the name. When the table is created, these changes will be shown to you and you will have the option of deleting the table immediately at that point. If you do nothing, the table will be created with the changes shown. 5.6 Customizing NaviServer Forms The simplest way to customize Entry, Update, and Search forms is to edit them with NaviPress and save tiiem to anotiier location. While this works fine for simple cases, you can not do it for update forms. Another way is to add information about the individual columns to the ns_columns table using its column_htmltag_type and column_htmltag_data columns. These two columns control what widgets are used for table columns in Search, Update, and Entry forms. The following are a lists of htmltag_types: SELECT, SELECTORNULL Forms use select box. Values are literals separated by spaces in the htmltag_data. Any character can be escaped with a backslash, or individual values containing spaces can be enclosed in single quotes. If you want users to be able to insert a NULL value, then use SELECTORNULL. SELECTSQL, SELECTSQLORNULL Forms use a select box, but htmltag_data contains an SQL statement that returns one column of rows, and is used to modify the form when accessed. For example, the ns_permissions table uses select user jname from nsjusers; so users can only enter legal user names. Page 5-8 95 The NaviServer Examples: Building a Database Application RADIO, RADIOORNULL Same as SELECT and SELECTORNULL, except the htmltag_data are instantiated as radio buttons. TEXTAREA, INPUT The widgets used here are TEXTAREA and INPUT. The htmltag_data are HTML options. For example, a user might use ROWS=6 COLS=40 for a comment field. AUTOINCR This only applies to columns of type integer. Entry forms will have a default value 1 larger than the maximum number in the column already. This is particularly useful when you want an arbitrary (but unique) number associated with each record. The html_tagdata is ignored. Take a look at the ns_columns table for examples of most of these. 5.7 Examples: Building a Database Application 5.7.1 Creating a table for Problem Reports This section will provide you widi an example of creating a problem report table to allow users to easily report problems. The server will automatically provide URL's for Entry forms and Search forms for your table. First, from a Page Window, choose the menu item Tools->Server Administration->General. Under die Tables heading, select Add New Table to open a form for creating a new table. The first section to fill out in the table form contains general information about the table. This includes the table name, a description of me table, and a check box to determine if the table is searchable. Since this table will be for problem reports, enter problem report in the Name field. In The Description field, enter Problem Reports. You will want people to be able to easily search this table, so leave Table is Searchable selected. The next sections contain column descriptions. In this example, you will be using four columns. For each column, you will need to enter it's name, type, description, and select whedier you want the column to be not null, unique, and indexed. The first column in the example will contain a severity rating of the problem. Enter problem severity in the Name filed, and set the Type to integer. In the Description field, enter Severity of Problem. Every problem will need a severity, but different problems can have the same severity, so select not null, but don't select unique. This problem will probably be searched for by severity quite often, so select index. The NaviServer 96 Page 5-9 Examples: Building a Database Application The second column will contain a description of the problem. Enter problem_descήption in the Name field, and set the Type to text. In the Description field, enter Description of Problem. Every problem will need to have a unique description, so select not null and unique. Since this is a large text field that will most likely be searched with the like or contains operators (see section 5.3 "Searching the NaviServer" on page 5-3), indexing would not be helpful. Do not select index. The third column will contain the name of person reporting the problem. Enter problemjreporter in the Name field, and set the Type to text. In the Description field, enter Name of Problem Reporter. This field can be left blank, so don't select not null. Also, this field does not need to be unique (the same person can report multiple problems) so don't Select unique. Do not select index either, since this is a less common way to look up problems. The fourth, and final column, will contain the date the problem was reported. Enter problem_date in the Name field, and set the Type to date. In the Description field, enter Date Problem was Reported. This field always needs an entry, however each entry does not need to be unique (you can have several problems from the same day), so select not null, but don't select unique. This is a common way to look up problems, so select index. You have now defined all die columns for this table, so go to the bottom of the column sections and click Create Table. An entry for and link to the form for the table you created will now be added to d e Search Server page. The URL for this form is /NS/GetEntryForm/problem_reports, where NS is the NaviServer directory. 5.7.2 Customizing Form Appearance You may feel that the forms you created are a bit bland in appearance. If you want, you can save them to another location and edit them using NaviPress. Note that when you do this, since the form isn't generated fresh each time someone asks for it anymore, the default report date won't always be the current date. Another way to customize the appearance of a form is by editing die entries in the nsjcolumns table. These control the widgets that the NaviServer uses for each column when it builds die form. So open the UKL/NS/GetSearchForm/ns_columns. Get all the columns where columnjtablename is problem jreports. The NaviServer will show you a table with 4 rows; one for each column in the problemjreports table. By default, columns of type text show up in forms as single line HTML INPUT widgets. To make the problem_description column show up as an HTML TEXTAREA, click on the link at the beginning of the problemjdescription line to update tiiat record. Then change the columnjitmltag ype to TEXTAREA, and type ROWS=6 COLS=50 for the column itmltagjdsta. Page 5-10 97 The NaviServer NaviLinking 5.73 Pointing to Forms The reason the problemjreport was built as die example was to allow people browsing the NaviServer to report problems. Goto the helpdesk page of the application blue print. Select the text that says Report a Problem. Using the menu item Elements->Link, link to the URL http://yourhost/NS/GetEntryForm problem_reports. If you wanted to link something directly to the search form, you would use http://yourhost/NS/GetSearchForm/ problemjreports. 5.8 NaviLinking Any pages indexed on d e NaviServer, whether they are local or remote, are available for NaviLinking. Just bring up a Page Window and chose the menu item Tools->NaviLink. Choose the NaviServer you want to link against. NaviPress sends your page to the server, and the server applies natural language processing technology to identify some potential hyperlinks that you could add to die page. You will then be able to easily go through the links and decide which wants you want to use. 5.9 Security Access to the NaviServer can be controlled at several levels. You are permitted to look at but not modify certain pages, while groups of users can be defined and allowed to search certain tables in the database. 5.9.1 Users and Groups The NaviServer stores all user and group information in 3 tables in the database: 1. Table ns_users: • user_name • user_passwd • user_defgroup 2. Table ns_groups: • group_name • group_description 3. Table ns_groups2users: • group_name • user_name These tables are maintained in exactly same way as other tables; Entry Forms, Update Forms, and Search Forms. The NaviServer 98 Page 5- 1 1 Security The user nsadmin is a superuser and can access anything on the server. Passwords are not encrypted, but only die nsadmin can look at or modify any of these three tables. 5.9.2 Protecting URLs There are two tables that deal with protecting individual URLs and whole URL trees. 1. Table ns_permissions: • permission_method • per ission_url • permission_user • permission_group • permission_user_ok • permission_group_ok • permission_world_ok 2. Table ns_methods: • method_name • method_alias The ns_methods table tells what methods considered equivalent. By default, BROWSE=HEAD=GET DELETE=PUT That is, anyone who has permission to PUT an URL has permission to DELETE it. Before operating on an HTTP request, the server determines if the user has access to that URL: 1. Find the relevant row in the ns_permissions table. If an exact match is not found for the URL, the tail is pared down until a match is found. For example, if there is not match for /products/cereals/raisinJbran.htmV , then the server looks for a row where permission_url = /products/cereals' . By default, the server comes with a row that says GET on V is open to the world. If no relevant row is found, access is denied (forbidden). 2. If permission_user_ok, permission_group_ok, and permission_world_ok are all false, access is denied (forbidden) 3. If the permission_world_ok is true, access is permitted 4. If the request did not come in with authorization data, access is denied. 5. The user and password are verified. If there is no password specified in the database, any password is accepted. Page 5- 12 99 The NaviServer Costs 6. If permission_user_ok is true and the permission_user is the username that came in with the request in the authorization data, access is permitted. 7. If permission_group_ok is true and the usemame that came in with the request is a member of the permission_group (based on the ns_groups2users table or the user's default group) then access is permitted. 8. Otherwise, access is denied. Permission data is cached in memory on the server, but is refreshed whenever there is a change to any of the permission tables. 5.93 Using NaviPress to Set Permission This section talks about using NaviPress to set permissions for particular pages or MiniWebs. Under the Tools->Server Administration menu, users can choose one of the following items: • GET permissions... • PUT permissions... • POST permissions... If a permission row for that page (and that method) already exists, the user gets an UpdateForm and can modify the data. Otherwise, the user gets a fresh permission EntryForm. 5.10 Costs 5.10.1 Setting up costs The cost model and the permission model are very similar. Any costs associated with pages that do not require any authorization are ignored. That is, the server does not charge for public pages. By default, cost accounting is disabled, and must be enabled at startup with the -A option. There are two tables dealing with costs and charges: 1. Table ns_costs: • cost_method • cost_url • cost amount The NaviServer 100 Page 5-13 Example: Managing Documents 2. Table ns_charges: • charge_user • charge_cost • charge_when When an HTTP request comes in, the NaviServer uses the same algorithm as the permissions code to find an appropriate row in the ns_costs table. If the server can't find an exact match for the method and URL, then it pares off the tail of the URL until it does. If the server can't find any match, the it does not charge the user. If the server does find a match, it inserts a row into the ns_charges table for the transaction, where the charge_cost is the cost_amount. 5.10.2 Viewing charges NaviServer administrators can view the charges by searching the ns_charges table or the ns_total_charges view which conglomerates all the charges for each user. 5.10.3 Using NaviPress to Set Costs This section deals widi using NaviPress to set costs for particular pages or MiniWebs. Setting costs with NaviPress is done almost exactly as setting permissions. Under the TooIs->Server Administration menu, users can select one of the following items: • GET Cost... • PUT Cost... • POST Cost... If a Cost for that page (and method) already exists, the user gets an UpdateForm and can modify the data. Otherwise, the user gets a fresh cost EntryForm. 5.11 Example: Managing Documents 5.11.1 Searching through publications. Currently, the blueprint contains an archive of net news. Some of these articles will be more interesting to your customers than others. For example, if your company produces special fonts, you may want to separate out and enrich any news articles that talk specifically about fonts. Click the Search icon on the tool bar, and search all the pages on your server by following links labeled ns_default_collection. To search the full text of all the pages for articles about fonts, type the word font into die input box on the same line as the word nsjbody. To remove any articles from the tex news group, select ns_url'~ not like tex%. By default, the NaviServer returns results in relevance-ranked order. Following the second link brings up a page titled Re: Info about Frame for NT needed and highlights all the occurrences of the word font. Page 5- 14 J J The NaviServer Describing Pages 5.11.2 NaviLinking Pages that contain a number of useful hyperlinks make the best use of the web. Hyperlinked pages give the reader immediate suggestions for where to go for more information. To help authors create hyperlinked documents, the NaviServer has a feature called NaviLinking that will suggest potential hyperlinks for a page. To use NaviLinking, click the Smart icon on the toolbar. NaviPress will send your page to the NaviServer for analysis after which a dialog pops up. The. first selection list contains all the potential anchors (derived from the page) for the links. Clicking on an anchor will highlight it in the page text and show the pages it could link to in the bottom selection list. To see the page with relevant terms highlighted, click Show Page. To insert the link into your page, click Apply. In this case, links from TrueType fonts and from Adobe Type Manager might add value to the document. 5.113 Publish Save the newly hyperlinked document back to where it came from with File->Save or use File->Save As to save it to a new location on the server. 5.11.4 Setting Permissions and Costs To restrict the users that can view the newly hyperlinked document, choose Tools->Server Administration->Get Permissions. This will bring up an Entry form for permissions data mat will control who can view this page. Change die permissionjuser to your name, if you have a user_name, or nsadmin if you don't. Change the permission _group to users. Select permissionjuser jok true, permission _group_ok true, and permission /orldjak false. Press the Enter Data button. Now only members of the users group can look at this page. To restrict the entire dtp tree, go to the Tools->Server Administration->General page, and follow the link to add new permissions data. Make the permissionjnethod GET and the permissionjurl dtp, and fill the rest of the form exactly as you did above. Now the whole /dtp hierarchy is protected. To put a cost on the page, choose Tools->Server Administration->Get Costs. Just fill in the amount, and every time anyone looks at this page, a charge is recorded in the nsjcharges table. 5.12 Describing Pages If you want to associate metadata with a page, choose die menu item Tools->Describe... in NaviPress. This will bring up a list of the metadata tables that can be used to describe the page. Select one of those links. You'll get an EntryForm with the column ns_url already filled in with the page you're describing. There will be an extra check box at the bottom. The NaviServer 102 Page 5-15 Archive Versioning If checked, the NaviServer will go get the full text of the URL and index it locally. 5.13 Archive Versioning When the server is started in archiving mode (-A), all saved pages are stored away in the ns_archives table. This requires extra disk space, but lets users reload previous versions of the page and all its inlined assets. To see all the old versions of a page stored on the server, insert /NS/ArchiveVersions after the host (and port if its there) in die URL. For example, http : //navisoft. com/index, html becomes http : / /navi soft . com/NS/ArchiveVers ions /index. html To go directly to the page as it existed at a given time, insert /NS/Archive/ YYYYMMDDHHMMSS. For example, http://navisoft.com/index.html on Feb 22, 1995 becomes: http : / /navisoft . com/NS/Archive/19950222000000/index .html 5.14 Logging If the server starts up in the foreground (-T), then both kinds of logging information go to standard output. If the server starts up in the background, then by default the logs get written to /usr/adm/nsd-access.log and /usr/adm/nsd-error.log. 5.14.1 Access log The NaviServer records who did what in CERN standard logging format. When the server is run in the background, the default location is /usr/adm/nsd-access.log. 5.14.2 Error log The NaviServer reports problems like bad data in die database, disk errors, and (shudder) bugs in die code in diis log. When put into the background, the default location is /usr/ adm/nsd-error. log. Page 5- 16 103 The NaviServer NaviServer System Tables 5.15 NaviServer System Tables This section provides a list of the actual SQL used to create each of the NaviServer system tables: create table ns_tables ( table_name text not null primary key, table_issearchable boolean default 'f , table_maxorderby int default 1, table_ismeta boolean default 'f, table_description text, chec (ns_table_exists(table_name) and table_ismeta = ns_table_ismeta(table_name) ) ) create table ns_columns ( column_table text not null, column_name text not null, column_description text, column_htmltag_type text, column_htmltag_data text, unique(column_table, column_name) , check(ns_colu_nr._exists(colu_t_n_table,column_name) ) ) create table ns_groups { group_name text not null primary key, group_description text ) create table ns_users ( user_name text not null primary key, user_pass d text, user_defgroup text not null references ns_groupε ) create table ns_groups2users ( group_name text not null references ns_groups, user_name text not null references ns_users, unique(group_name,user_name) ) create table ns_methods ( method_name text not null primary key, method_alias text, check(method_alias = upper(method_alias) ) ) The NaviServer 104 Page 5-17 NaviServer System Tables create table ns_permissions ( permission_method text not null, permission_url text not null, permission_user text references ns_users, permission_group text references ns_groups, permission_user_ok boolean not null, perτnission_group__ok boolean not null, permission_world_ok boolean not null, unique(permission_url, ρermission_method) , check(permission_method = upper(permission_method) ) ) create table ns_costs { cost_method text not null, cost_urLtext not null, cos _amount int default 0, unique(cost_method, cost_url), check(cost_method = upper(cost_method) ) ) create table ns__charges ( charge__user text references ns_users, charge_cost int not null, charge_when timestamp default current_timestamp ) create table ns_config ( config_name text not null primary key, config_value text } create table ns_default_collection ( ns_url text not null primary key, ns_title text, ns_bodydoc not null ) create table ns_archives ( archive_path text not null primary key, archive_type text, archive_lo large_object ) Page 5-18 105 The NaviServer APPENDIX A Page Window, Menus, and Icons A.l NaviPress Page Window The following figure of the page window: Page Window. Menus, and Icons 106 Page A- l A.1.1 Toolbar The following icons are the toolbar icons Cut z Copy m# Paste Descπbe Page Describ Search Server S-Mrdτj Page A-2 107 Page Window, Menus, and Icons A.1.2 Overview of Menus When a page window is active in NaviPress, the following menus are active. There are platform specific menu accelerator keys: File Edit Elements Format Jool Browse Window Help Page Window, Menus, and Icons 108 Page A-3 A.2 The File Menu The File Menu contains application file operations, such as opening, saving, and printing. A.2.1 New MiniWeb Creates a new MiniWeb and and a new Page. The new page will be in the new MiniWeb. A.2.2 New Page Creates a new page. A.2.3 Open Invokes a dialog box which allows you to open a file. The file may either be on another server, or a local file. If the file is a web page or a MiniWeb, then it will be opened normally. If the file is a sound or video file, then an attempt will be made to launch an external viewer or player. If none is available you will be asked if you want to save the file. If the file is a graphic image, then an attempt will be made to launch an external viewer. If none is available and d e file is either a GIF, JPEG, or XBM, then a new Page Window will opened containing the image. Otherwise you will be asked if you want to save the file. Filters can be applied to the file to translate it into some odier format. The available filters can be found under menu item Tools •> Preferences -> Input Filters. A.2.4 Close Closes the current page. If the changes to the page have not been saved, a dialog appears asking you if you would like to Save or Discard the page modifications, or Cancel the closing of the page. A.2.5 Save Saves the current page. If the file has not previously been saved, die Save As dialog appears, allowing you to save the document locally into a miniweb, or to a remote server. A.2.6 Save As Invokes the Save As dialog. This dialog allows you to save d e page to another location, and to change die file format if you want. You can also apply an external filter to the file. The available filters are defined in Tools -> Preferences -> Save Filters. If the page contains images, the images can be saved with the page. If the images are not saved with die page, dien the new page will have links to the original images. If the images are copied with the page, tiien the new page will have links to the local copies of the images. Page A-4 JQ Page Window, Menus, and Icons A.2.7 Import Invokes the Import dialog. This allows you to insert the contents of a text file into the current page. The text options are preformatted (all new lines are preserved) or regular text (words are wrapped and the new lines are removed). A.2.8 Print Setup Invokes a platform-specific dialog, which allows you to define printer options and print settings. A.2.9 Print Invokes the print dialog. This allows you to print the current page, as either PostScript or text. A.2.10 Exit Closes the NaviPress application. If miniwebs or pages have not been saved, you are prompted to save diem. If you have created any new MiniWebs tiiat are empty, you will asked if you want to delete them. A The Edit Menu The Edit Menu contains operations for the editing of pages including Cut, Copy, Paste, Find / Replace. A.3.1 Undo Removes the latest operation. You should be warned that some operations may not be undone. Subsequent selections of Undo will undo progressly older changes to the page, until the original page is restored. A _2 Redo Reverses an undo. Redos may be done as many times in a row as undos have been done. A.3.3 Cut Places the current selection on the clipboard, while simultaneously removing it from the page. A.3.4 Copy Places the current selection on to the clipboard, leaving die current page unchanged. A.3.5 Paste Either inserts the contents of the clipboard at the current insertion point or replaces the Page Window, Menus, and Icons HO Page A-5 current selection with the contents of the clipboard. A.3.6 Clear Removes the selection from the page. Unlike the operations, Cut and Copy, the Clear operation does not copy the contents to the clipboard. A.3.7 Select AH Selects all the contents of the current page. A.3.8 Copy URL Copies the URL of the current page. Pasting this URL into another page automatically creates a link between the pages. A.3.9 Paste URL If the previous Copy operation was Copy URL, the menu item Paste URL is enabled. Pasting an URL onto a selection will make that selection a link to the page the URL was copied from. Pasting an URL at an insertion point (if no text is selected) will insert the Tide of the copied page, and will make the title a link to that page. A.3.10 Find / Replace Invokes the Find / Replace dialog, which allows you to find and/or replace text in the current page. A3.ll Find Next Repeats the current Find operation. A.4 The Elements Menu The Elements Menu contains menu item operations for insertion and/or creation of HTML page elements. A.4.1 Get Attributes... Invokes a dialog most relevant to the selection. For example, if linked text is selected, die Link dialog will be invoked. If an image is selected, then the Image dialog is invoked. A.4.2 Horizontal Rule Inserts a ruled line at die current insertion point. The appearance of the rule line is defined by the applied style sheet. A.4.3 Forced Line Break This is equivalent to pressing SHIFT-RETURN, which will cause a line break at the insertion point. This puts the insertion point one space below the current line. Pressing just RETURN puts the insertion point two spaces below the current line. Page A-6 1 1 ] Page Window, Menus, and Icons Note that lines separated by line breaks are part of the same paragraph. A.4.4 Image Invokes the Image dialog. This dialog allows you to insert and align an image at the cursor insertion position. The alignment options enable you to align die inserted picture with a line of text in three positions: top, middle, or bottom. A.4.5 Image Map Invokes the Image Map dialog for the selected image. This dialog enables you to create an Image Map asscotiated widi a given image. Image maps allow you to create links in different parts of an image. A.4.6 Link Invokes a dialog box that enables you to create a link to either a local file, a file within a miniweb, or to a file on the Web. The current selection becomes the anchor for this link. If the current selection already contains a link, you have several additional options. You can: • remove the link (leaving the selection intact) • shorten the selection, such that only the link itself is selected • copy the URL of the current link to be pasted to another location A.4.7 Anchor Invokes a finder dialog box, which enables you to attach a marker name to the selection. You can then link to that marker using the notation. A.5 The Format Menu The Format Menu contains operations for formatting elements, related to text, within a page. This ranges from character styles, including headings and paragraphs, to lists and forms. A.5.1 Remove Format A.5.2 Special Style Enables you to apply particular style to a character selection. The Special Style Page Window, Menus, and Icons 112 Page A-7 submenu items are the following: Plain text (no emphasis) Bold Italic Underline Fixed Pitch (a monospaced font such as Courier) Subscript (smaller font, lower baseline) Superscript (smaller font, higher baseline Citation (italic) Code (monospaced font) Definition (bold) Emphasis (bold) Example (plain text) Keyboard (monospaced font) Sample (monospaced font) Strong (bold and red) Variable (monospaced font) A.5.3 Heading The Heading menu item contains a submenu of six defined headings and a "Normal"format selection. The selection of a particular submenu element will apply to your character selection. Normal removes a heading definition from the character selection. A.5-4 Paragraph The Paragraph menu item contains a submenu of three simple paragraphs and a "Norma 'format selection. The "Normal" selection removes all Paragraph formatting. The Paragraph submenu items are the following; • BlockQuote paragraphs are for large (extended) quotations. This selection indent the selection, separating it from the surrounding text. • Preformatted paragraphs generate text in a fixed-width font and cause spaces, new lines and tabs to be displayed in the same locations as similar to the source HTML file. This may be used for code samples in which all new lines, tabs and otiier whitespace must be preserved. • Address is a signature type line of text. Addresses usually go at the bottom of the Web page and are used identify who authored the page, who to contact for more information, date, copyright and other notices. Page A-8 113 Page Window, Menus, and icons A.5.5 List The List menu item contains a submenu consisting of tiiree types of lists, a "Normal" format selection, and alternating selections - Term and Definition. • Unnumbered lists are bulleted • Numbered lists are numbered • Definition lists is a list that is created by alternating a Term and a Definition. The definition formats the selected text to a new line. Inside a numbered or an unnumbered list, the menu item selection of "Term" returns a new list element. The keyboard equivalent of the 'Term" selection is the return key. A.5.6 Form Invokes a Form dialog box. This dialog box allows you to select the form handler location (URL). This is the a script that processes a form (the cgi script). Also included in this dialog box, are the methods of form submission. The submission method is defaulted to Get, with an optional Post. A form elements palette is associated widi a form. This includes a selection of tools for creating radio buttons, check boxes, single- and multi-line text fields, selection lists, and picture fields. A.5.7 Style Sheet Invokes the Style Sheet dialog box. This dialog box enables you to define and change the appearance of the elements on screen. A style sheet is a set of mappings between page elements, such as headings and lists to font and font size and elements. The style for a new miniweb page is set to the Navipress default. From this dialog box, the default style sheet can be edited, a new style sheet can be created and a style sheet selection can be applied to the current page, A.6 The Tools Menu The Tools Menu item contains the tools for checking and testing information about or elements within the current page, or miniweb. This menu also contains the application preferences. A.6.1 Show HTML Opens a read-only window containing the source for the current page in HTML (HyperText Markup Language). This file can be saved as a text text. A.6.2 NaviLinks Opens a dialog box that provides suggestions of possible links from the current page using the NaviLinks service on a NaviServer. To specify the location of the server, you may either enter the location name in the Location text field, or they may select Page Window, Menus, and Icons \ \^ Page A-9 a location for the default list. The default list can be found under preferences, "Tools -> Preferences -> Destinations". A.6.3 Check Links Invokes a dialog box which enables you to check each link in the current page, mak¬ ing sure that the page or location (URL) that the link points to is valid. A.6.4 Describe Page Describe Page and Search Server functions are complemenatry. The Describe Page menu item invokes a dialog box that enabes you to input data for the for Search and Retrieval service. Features include the capability to select a NaviServer, a data description type, and input a descripton (Title, Author, and Subject). To specify the location of the server, you may either enter the location name in the Location text field, or they may select a location for the default list. The default list can be found under preferences, "Tools -> Preferences -> Destinations". A.6.5 Search Server Search Server and Describe Page functions are complemenatry. The Search Server menu item invokes a dialog box that enables you to query for data from the Search and Retrieval service. Features include the capability to select a search type, fill out the forms with query data, and the retrieval of a list of results with respect to your input query data. To specify the location of the server, you may either enter the location name in the Location text field, or they may select a location for the default list. The default list can be found under preferences, "Tools -> Preferences -> Destinations". A.6.6 Server Administration The Server Adminstration menu item are the adminstrative functions. See die tutorial on NaviServer for a description. A.6.7 General (Preferences) Contains preferences specific to NaviPress, including whether to load remote images with each document, a directory to cache files in, your email address, and proxy and name servers. A.6.8 Extensions MIME (Preferences) Contains a list that associates file name extensions (such as .html or .gif) with file MIME types. This list is only used by NaviPress when opening local files or receiving files from non-Web servers (for example, FTP). Page A- 10 ■ 15 Page Window, Menus, and Icons A.6.9 MIME Viewer (Preferences) Contains a list that associates file MIME types (such as image/jpeg or text/html) with external programs that can view or play those files. If NaviPress itself cannot view or play the file, the external viewer is started up based on this list. A.6.10 Save As Filters (Preferences) Allows you to specify external filters (executeable programs) that can translate a file from HTML into some other format when that file is saved. You can choose a filterfrom this list when you save a file using "Save As... "Preferences / MiniWeb Icons... associates icons in the MiniWeb view with a file's MIME type. A.6.11 MiniWeb Icons (Preferences) Allows you to list that associates file MIME types (such as image/jpeg or text/html) with an icon location. A.6.12 NaviServer (Preferences) Defines a set of default NaviServer destinations which can be used to search pages, save pages or miniwebs to remote servers, or create NaviLinks for pages. A dialog allows you to specify both the location (URL) and a more easily understood alias for that destination. A.6.13 Delete Enables you to delete any file using a delete chooser dialog box. This file can be either local or on a remote server. A.7 The Browse Menu The Browse Menu contains operations for browsing the web pages, both locally and on the remote World Wide Web. A.7.1 Backward When browsing, the Backward menu item moves you backward to the previously visited pages. This is based on a list found in die Global History. A.7.2 Forward When browsing, the Forward menu item moves you forward through the pages previously visited. This is based on a list found in the Global History. A.7.3 Stop Allows you to cancel the action of browsing forward or backward through the visited pages found in your Global History, (see Backward, Forward). Page Window, Menus, and Icons 1 ] 6 Page A-l 1 A.7.4 Reload Page Reloads the current page and all its images from the remote server or from the your local hard disk. A.7.5 Global History Brings up a dialog box with a global history list. This is a list of all the pages you have browsed during die current session with Navipress. You are able to return to any of the listed pages by selecting the page name from the list and clicking on the button "Fetch". Fetch places the selection into a new window. A.7.6 Hot List Provides die capability to add, remove, and rearrange items in your hot list. The "hot list" is a forum which enables you to store the names and location of pages that they would like to revisit, similar to a bookmark. You can also create labels for the hot list items. You are able to go to the location found in their hot list by selecting the name of the location from the hot list, and clicking on the button "Fetch". Fetch places the selection into a new window. A.7.7 Add to Hot List Adds the Location (URL), of the current page, to your hot list. A.8 Window Menu The Window menu contains all the windows open in NaviPress. By selecting a window, it becomes active. It also contain platform-specific tools for arranging windows such as Tile and Cascade. A.9 Help Menu The Help menu contains pages for help, tutorials, and die About Box. Page A- 12 \ \η Page Window, Menus, and Icons APPE DIX B MiniWeb Window, Menus, and Icons B.l NaviPress MiniWeb Window The following figure of the Mini Web window: MiniWeb Window, Menus, and Icons \ \ Page B-l B.l.l Toolbar The following icons are the MiniWeb toolbar icons: Page B-2 1 19 MiniWeb Window, Menus, and Icons B.1.2 Overview of Menus When a page window is active in NaviPress, the following menus are active. There are platform specific menu accelerator keys: File Edit Uiew ϊool Browse Window Help B.2 The File Menu The File Menu contains application file operations, such as opening, saving, and printing. B.2.1 New MiniWeb Creates a new MiniWeb and New Page within tiiat MiniWeb. B_2_2 New Page Creates a new page. MiniWeb Window, Menus, and Icons 120 Page B-3 B.2.3 Open Accesses a chooser dialog box which allows you to open an existing MiniWeb or page. Remote mini webs and pages are specified by location (URL). NaviPress refers to the URL as "Location". Local miniwebs and pages are specified by their file name. MiniWebs and pages need to be processed to be opened. An example would be HTML. HTML files can be opened as text (as opposed to being parsed and formatted). In addition, filters can be applied to the file to translate it into some other format. The available filters can be found under menu item "Tools -> Preferences -> Input Filters". B.2.4 Close Closes the current page. If the changes to the page have not been saved, a dialog appears asking you if they would like to Save or Discard the page modifications, or Cancel the closing of the page. B.2.5 Save Saves the current page. If the file has not previously been saved with a file Title and to a Location, the Save As dialog appears, allowing you to save the document locally into a miniweb, or to a remote server. B.2.6 Save As Accesses a chooser dialog box, Save As. This dialog box allows you to save the page to another Title and Location, or to a different format (Text, HTML, or RTF). You can also apply an external filter to the file. The available filters are defined in "Tools -> Preferences -> Save Filters". If the page contains images, the images can either be saved with die page or refer to them remotely. B.2.7 Import Opens a chooser dialog box, allowing you to insert the contents of a text file into the current page. The text options are preformatted (all new lines are preserved) or regular text (words are wrapped and die new lines are removed). B.2.8 Exit Closes the NaviPress application. If miniwebs or pages have not been saved, you are prompted to save them. B.3 The Edit Menu The Edit Menu contains operations for editing the MiniWeb including adding and removing pages. PageB-4 J21 MiniWeb Window, Menus, and Icons B .1 Cut Places the current selection and its location (URL, if there is one)on to the clipboard, while removing it simultaneously from the current MiniWeb. B.3.2 Copy Places the current selection and its location (URL, if there is one)on to the clipboard, leaving the current selection unchanged. B .3 Paste Inserts the contents of the clipboard at die into the MiniWeb Window. The file will be represented by an icon. B.3.4 Clear Removes the currently selected MiniWeb element from the MiniWeb. If links to that page still exist, die page icon will not be removed; instead it will grey. That page can¬ not be totally removed from the miniweb unless all links to it are broken. B3.5 Copy URL Copies the URL, refered to as the Location, and die title of die current page. Pasting this URL into MiniWeb automatically creates a link between the pages. B3.6 Paste URL If the previous Copy operation was Copy URL, the menu item Paste URL is enabled. Pasting an URL results in one of three selections: • Pasting only the current page. • Pasting an URL and it's related links. B3.7 Set Stationary B.4 The View Menu The View Menu contains menu item operations for insertion and/or creation of HTML page elements. B.4.1 Clean Up Cleans up arrangement of your MiniWeb Window. B.4.2 Zoom In Makes the view of the MiniWeb larger (less of it can be displayed). Only a previously- reduced MiniWeb can be zoomed in. MiniWeb Window, Menus, and Icons 122 Page B-5 B.4.3 Zoom Out Makes the view of the MiniWeb smaller so more of the MiniWeb can be displayed. B.5 The Tools Menu The Tools Menu item contains the tools for checking and testing information about or elements within the current page, or miniweb. This menu also contains the application preferences. B.5.1 Describe MiniWeb Describe MiniWeb and Search Server functions are complemenatry. The Describe MiniWeb menu item accesses a dialog box that enabes you to input data for the for Search and Retrieval service. Features include the capability to select a NaviServer, a data description type, and input a descripton (Tide, Author, and Sub¬ ject). To specify the location of the server, you may either enter the location name in the Location text field, or they may select a location for the default list. The default list can be found under preferences, "Tools -> Preferences -> Destinations". B.52 Search Server Search Server and Describe Page functions are complemenatry. The Search Server menu item accesses a dialog box that enables you to query for data from the Search and Retrieval service. Features include die capability to select a search type, fill out the forms with query data, and the retrieval of a list of results with respect to your input query data. To specify the location of the server, you may either enter the location name in d e Location text field, or they may select a location for the default list. The default list can be found under preferences, "Tools -> Preferences -> Destinations". B.5 Server Administration The Server Adminstration menu item are the adminstrative functions. See die tutorial on NaviServer for a description. B.5.4 General (Preferences) Contains preferences specific to NaviPress, including whether to load remote images wid each document, a directory to cache files in, your email address, and proxy and name servers. B.5.5 Extensions/MIME (Preferences) Contains a list that associates file name extensions (such as .html or .gif) with file MIME types. This list is only used by NaviPress when opening local files or receiving Page B-6 123 MiniWeb Window, Menus, and Icons files from non-Web servers (for example, FTP). B.5.6 MIME Viewer (Preferences) Contains a list that associates file MIME types (such as image/jpeg or text/html) with external programs that can view or play those files. If NaviPress itself cannot view or play the file, die external viewer is started up based on this list. B.5.7 Save As Filters (Preferences) Allows you to specify external filters (executeable programs) that can translate a file from HTML into some other format when that file is saved. You can choose a filter- from this list when you save a file using "Save As..."Preferences / MiniWeb Icons... associates icons in the MiniWeb view with a file's MIME type. B.5.8 MiniWeb Icons (Preferences) Allows you to list that associates file MIME types (such as image/jpeg or text/html) with an icon location. B.5.9 NaviServer (Preferences) Defines a set of default NaviServer destinations which can be used to search pages, save pages or miniwebs to remote servers, or create NaviLinks for pages. A dialog allows you to specify both the location (URL) and a more easily understood alias for that destination. B.5.10 Delete Enables you to delete any file using a delete chooser dialog box. This file can be either local or on a remote server. B.6 The Browse Menu The Browse Menu accessing your Global History and Hot List. B.6.1 Global History Brings up a dialog box with a global history list. This is a list of all the pages you have browsed during the current session widi Navipress. You are able to return to any of the listed pages by selecting the page name from the list and clicking on the button "Fetch". Fetch places the selection into a new window. B.6.2 Hot List Provides die capability to add, remove, and rearrange items in your hot list. The "hot list" is a forum which enables you to store the names and location of pages that they would like to revisit, similar to a bookmark. You can also create labels for the hot list items. MiniWeb Window, Menus, and Icons 24 Page B-7 You are able to go to the location found in their hot list by selecting the name of the location from the hot list, and clicking on the button "Fetch". Fetch places the selec¬ tion into a new window. B.63 Add to Hot List Adds the Location (URL), of the current page, to your hot list. B.7 Window Menu The Window menu contains all the windows open in NaviPress. By selecting a win¬ dow, it becomes active. It also contain platform-specific tools for arranging windows such as Tile and Cascade. B.8 Help Menu The Help menu contains pages for help, tutorials, and the About Box. Page B-8 125 MiniWeb Window, Menus, and Icons APPENDIX c Installation C.l NaviPress Installation The following are the steps necessary to install NaviPress on your system: C.l.l Macintosh Installation 1. Ftp to ftp.aol.com with the username navibeta and die password beta.web. 2. Cd to the /beta/np directory. 3. Grab the file np-mac.bin 4. Create a folder on the Macintosh and drop the binary in it. Files created by Navi¬ Press will be placed in this folder. C.1.2 MS Windows Installation 1. Ftp toftp.aol.com with the username navibeta and d e password beta.web. 2. Cd to d e /beta/np directory. 3. Grab the file np-win.zip. Note tiiat this file has been compressed with PKZIP. 4. Create a directory for the client (e.g. C:\NPRESS) 5. Uncompress the file with PKUNZIP and place in the directory you created. C.1.3 Sun Installation 1. Ftp to ftp.aol.com with the username navibeta and the password beta.web. 2. Cd to die /beta/np directory. 3. Grab the file np-sun.tar.gz. Note that this file has been compressed with gzip. Installation 126 PageC- 4. Cd to any directory. 5. Extract the tar file with: % gunzip < tar_file | tar xvf - This will create a directory containing die client. 6. Place the directory in your PATH C.2 Running NaviPress The first time NaviPress is run the following dialog is invoked: If you tiien click OK you will get the following dialog: Mail address: wwwUser dork 1 - I Proxy: C aet, \ Name Server: ~~] Load Remote Pictures D Prefetch Pages D Unix Style Delete MiniWeb File type: <§> DOS O Mac C.2.1 Name Servers Machines on the net know each other by their IP Address, which is usually expressed as four numbers separated by dots. For example: 131.215.139.100 Page C-2 127 Installation However, the people who use these machines would much rather refer to them by a name, such as: tybal . caltech . edu When the net was small, there was a text file of mappings between names and addresses so that people could say tybalt.caltech.edu, and tiieir machines would know to contact I3I.2I5.I39.1W. Now that the net is much bigger, there are name servers which you can ask for the IP address corresponding to a given name. If the name server doesn't know offhand, it will repeat the question to other name servers, and give you whatever address they reply. This name server chaining allows you to look up the name of machines all over the net, but you still need to know an address for the first name server. If you don't already know your nameserver's address, ask your Network Administrator or Service Provider. C.2.2 Proxy Servers When attempting to reference an URL, a web client can either go and fetch the data itself, if has implemented die scheme (http:, ftp:, wais:, etc.), or it can make an HTTP request to a Proxy Server, which will fetch the data and return an HTTP response. NaviPress fetches htφ: and ftp: URLs itself, but will ask the proxy server to fetch all other kinds of URLs. This means that NaviPress will automatically work with new types of URLs as they are defined, but it also means that the proxy server entry in the menu Tools- >Preferences->General must be set to an HTTP proxy server (such as the CERN server, which also caches) in order to follow otiier kinds of links. 5.15.1 Copying Preferences On UNIX, a preference file, nαvipres.prf, is created in your user directory containing the preferences you set (proxy serwer, name server, etc.). If you want other users to default to your preferences without having to set them themselves, copy nαvipres.prf into the NaviPress directory. On die Macintosh and PC, the preference file is in the NaviPress folder. Copying this whole folder will copy the default settings. C NaviServer Installation The following are the steps necessary to install NaviServer 1. Ftp to ftp.aol.com with the username navibeta and the password beta.web. 2. Cd to die /beta/nsd directory. Installation 128 Page C-3 3. Grab nsd-beta.common.tar.Z. This compressed tar file contains NaviServer files common to all platforms. 4. Grab the compressed tar file for your platform: • Sparc SunOS: nsd-beta.sun4.tar.Z • Sparc Solaris: nsd-beta.solaris.tar.Z • Intel Solaris: nsd-beta.i86pc.tar.Z • HP HP UX: nsd-beta.hp.tar.Z 5. Log in as any user except root. 6. Define the NS_HOME environment variable to some new directory and cd to it: % setenv NS_HOME <some directory:* ; % m dir $NS_HOME % cd $NS_HOME 7. Extract the common tar file: % zcat < nsd-beta . common . ar . Z | tar xvf - 8. Extract the platform specific tar file: % zcat < nsd-beta . <platform> . tar . Z | tar xvf - 9. Reload die license you received from us with: % $NS_HOME/bin/nslicense If you need a license send email to jimbo@navisoft.com. 10. Start the database with: % $HS_HOME/bin/nsstartdb 11. Start a NaviServer in the foreground with: % $NS_HOME/bin/nsd - f 12. You can also start a server in the background on port 80 by logging in as root and using: # $NS_HOME/bin/nsd -u < ; user who owns NS_HOME> You may be interested in die $NS_HOME/bin/rc.nsd script. Page C~4 129 Installation INDEX A customizing forms 5-8 absolute link definition 4-2 Access log 5-16 definition lists 3-3 Add To Hot List 2-3 deleting icons in MiniWebs 4-8 adding pages to MiniWebs 4-4 deleting tables 5-6 anchors Describing Pages 5-15 creating 3-7 Double Clicking on Icons 4-7 Archive Versioning 5-16 Drag and Drop 4-7 Authoring 3-1 E B editing web pages 3-2 Back Button 2-3 Editing With MiniWebs 4-8 Browse button 3-4 Error log 5-16 browsing 2-1 exiting NaviPress 2-4 for links 3-7 browsing for graphics 3-4 files of unknown type icon 4-3 cached pages 2-3 fixing 4-5 charges 5-14 fixing links 4-5 Color Coding format borders 3-4 in MiniWebs 4-6 Format menu 3-2 column Formats 3-2 description 5-7 formats indexing 5-8 headings 3-3 name 5-7 lists 3-3 not null 5-7 special styles 3-3 type 5-7 forms unique 5-8 customizing 5-8 command line options Forward Button 2-3 for die NaviServer 5-2 contains operator 5-3 Copy icon 3-7 Get Attribute 3-5 copying MiniWebs 4-3 ghost files copying text 3-6 definition 4-2 Copying URLs 3-9 Global History 2-3 Costs 5-13 graphics costs importing 3-4 setting 5-14 links in, see image maps 3-8 Creating Anchors 3-7 H Creating Links 3-7 Headings 3-3 creating tables 5-6 Hide Border 3-4 creating web pages 3-1 highlighting page 5-5 Index 130 Page I INDEX home page unnumbered lists 3-3 definition 4-2 log setting 4-8 access 5-16 Hot List 2-3 error 5-16 hot spots in images 3-8 Logging 5-16 hypertext creating links 3-7 M Merging MiniWebs 4-5 MiniWeb Icon Color 4-6 icons 4-3 icons MiniWeb Button 4-8 colors of 4-6 MiniWeb terminology 4-2 double clicking on 4-7 MiniWeb Window 2-1 files of unknown type 4-3 description of 4-2 image files 4-3 MiniWebs 4-1 image maps 4-3 adding pages 4-4 sound files 4-3 button in Page Window 4-8 style sheets 4-3 color coding 4-6 video files 4-3 copying 4-3 web pages 4-3 copying URLs 4-8 Image dialog 3-4 deleting icons 4-8 image file editing with 4-8 icon 4-3 icon color 4-6 image map link color 4-6 icon 4-3 merging 4-5 Image Maps 3-8 pasting URLs 4-4 images saving 4-8 importing 3-4 links in, see image maps 3-8 N Importing Graphics 3-4 NaviLinking 5-11 importing text 3-6 NaviPress indexed column 5-8 starting 2- 1 inlined NaviServer 5-1 definition 4-2 command line options 5-2 system tables 5-17 not null 5-7 like operator 5-3 numbered lists 3-3 Link Color 4-6 links 4-5 O browsing for pages 3-7 options creating 3-7 command line for NaviServer 5-2 Lists 3-3 lists definition 3-3 Page Window 2-1 numbered 3-3 description of 2-1 Page II 131 Index INDEX Index 132 Page III INDEX tiding 3-2 Page IV 133 Index 134 hh Sat Mar 25 10:37:09 1995 Header Files for all Code -r--r -r--r -r--r -r--r--r-- -r--r -r--r -r--r -r--r -r--r--r-- -r--r -r--r -r--r -r--r--r-- -rw-r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r—r -r--r Sat Max 25 09:10:41 1995 Listing of Data Management Library Routines Provides vendor independent access to a commercial-off-the-shelf database management system. All database accesses are made through this library layer. lib Sat Mar 25 09:29:36 1995 Client Communications Layer Library that handles all communications tasks from the client to the server (or other servers). Creates, manages and disposes of connection requests and returns responses. -r—r -r--r -r--r -r—r -r--r -r--r -r--r -r--r -r--r -r—r -rw-r -r--r -r--r -r--r -r--r -r--r -r—r -rw-r -r—r -rw-r -r—r -r--r--r-- -r—r -rw-rw-r— -r--r -r—r—r— -r--r--r-- -rw-rw-rw- -r--r drwxrwxr-x -r--r -r--r -r--r -r—r -r--r -rw-r Files included for reference: crud.c : builds crud--create, retrieve, update, delete—structures. cruds are the main structure to hold requests. crudio.cxx: handles the client input/output stream. crudshim.c: runs a tas . docrud.cx : executes a crud request. lhtml.c: handles formatting and parsing HTML. local.cxx: handles local operations (as opposed to remote over the net) response.cxx: routines to handle returns from the server. str.cxx: routines to handles strands, main I/O stream. web.cx : builds http requests, builds TCP requests. lib Sat Mar 25 09:29:36 1995 xcom .c: TCP socket code. xdoc.c: routine to assist with directories for collections. xlocal.c: routines to mainpulate file/URL paths cross-platform. z p Sat Mar 25 09:31:43 1995 Natural Language Processing Library Routines to zone html, ste -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r Files included for reference: None. See prior art. nadlib Sat Mar 25 09:35:54 1995 Library of Scripts Routines used for administrative functions of the server. 19:12 . 19:04 .. 19:12 RCS 14:32 admin.tcl 18:21 archive.tcl 19:12 chores.tcl 20:53 init.tcl 18:21 mi.tcl 19:32 reinit.tcl 18:21 return.tcl 19:12 tables.tcl Files included for reference: archive.tcl: script that implements automatic version history of objects init.tcl: script used to register new operations. table.tcl: script used to automatically create tables from forms. nβd Sat Mar 25 09:48:13 1995 1 Main body of the core server and operations -r--r -r--r -r--r -r—r -r—r -r--r -r--r -r--r -r--r -r—r -r--r -r--r -r--r -r--r -r--r -r—r -r—r -r--r -r--r -r--r -r—r—r-- -r—r -r--r -r--r -r--r -r--r -r— -r—r -r—r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r--r -r—r -r--r Files included for reference: Describe.c: code that attaches descriptive indexes to addresses Fastpath.c: code that executes default operations, those that are not registered with the server GetForm.c: code to implement autogeneration of forms GetHilitedPage.c: code that highlights search terms in a page MoreLikeThis.c: code that does similarity search on pages Navlink.c: automatic generation of hyperlinks Ng2Hlinks.c: automatic generation of hyperlinks nad Sat Mar 25 09:48:13 1995 Ng2AnchorProb.c: automatic generation of hyperlinks TclOp.c: executes scripted operations, extensibility of server TypeCheck.c • verifies datatypes conform to standards for dbms hilite.c: used in highlighting search terms from queries mergepage.c. merges data from dbms into HTML forms, used on db updates nlink.c- automatic generation of hyperlinks nsd.c: main body of the server, place to register new C oeprations veπfys ■<jl Sat Mar 25 09:49:40 1995 1 SQL statements to build server DBMS structures -r—r 1 gww 1170 Feb 16 07:22 navidrop.sql -r--r 1 doug 14303 Mar 18 21:41 nsbuild.sql -r—r—r-- 1 gww 1137 Feb 15 12:26 nsdrop.sql -rw-rw-r-- 1 gww 2877 Feb 1 10:44 rollforward.a9-al0.sql Files included for reference: nsbuild.sql: builds a server DBMS and all of the structures used to manage content, do archiving, use forms with tables, etc. util Sat Mar 25 09:50:29 1995 Utility Routines -rw-r -r--r -r--r -r--r -r--r -r--r -r—r -r—r -r--r -r--r -r—r Files included for reference: None. praaa Sat Mar 2510:29:33 1995 Main body of code for the client User interface routines start with NP. -rw-r—r— 2213 Mar 22 16 11 NPAbout.c -r -r—r-- 3724 Mar 22 16 11 NPAbout .c -rw-r—r— 3100 Mar 22 16 11 NPAuthen.c -rw-r—r— 3501 Mar 22 16 11 NPChkLnk.c -rw-r—r— 3211 Mar 22 16 11 NPChoose.c -rw-r—r~ 2677 Mar 22 16 11 NPDest.c -rw-r—r— 4232 Mar 22 16 30 NPDoc.c -rw-r—r— 6127 Mar 22 16 11 NPDocMn.c -rw-r—r— 2313 Mar 22 16 11 NPError.c -rw-r—r— 4081 Mar 22 16 11 NPFindRp.c -rw-r—r— 3307 Mar 22 16 41 NPForm.c -rw-r—r— 2723 Mar 22 16 11 NPHistor.c -rw-r—r— 4720 Mar 22 16 11 NPHotLst.c -rw-r—r— 4183 Mar 22 16 11 NPlmgFld.c -rw-r—r-- 3744 Mar 22 16 11 NPInsImg.c -rw-r—r— 2602 Mar 23 15 13 NPLatin.c -rw-r—r— 3512 Mar 22 16 11 NPLink.c -rw-r—r— 7195 Mar 22 16 11 NPMap.c -rw-r—r— 4376 Mar 22 16 11 NPMime.c -rw-r—r-- 2697 Mar 22 16 11 NPNewStl.c -rw-r—r— 2930 Mar 22 16 11 NPNvLink.c -rw-r—r— 2561 Mar 22 16 11 NPOpnOpt.c -rw-r—r— 7237 Mar 22 16 30 NPPage.c -rw-r—r— 12323 Mar 23 14 55 NPPageMn.c -rw-r—r— 7958 Mar 22 16 11 NPPalet.c -rw-r—r— 5619 Mar 22 16 11 NPPr Gen.c -rw-r—r— 4030 Mar 22 16 11 NPRadio.c -rw-r—r— 4232 Mar 22 16 11 NPRefBy.c -rw-r—r— 4115 Mar 22 16 11 NPRe To.c -rw-r—r-- 3351 Mar 22 16 11 NPSavOpt.c -rw-r—r— 4812 Mar 22 16 11 NPSelLst.c -rw-r—r— 3282 Mar 22 16 11 NPSrc.c -rw- —r— 1095 Mar 22 16 11 NPSrcMn.c -rw-r—r— 4892 Mar 22 16 11 NPStlCha.c -rw-r—r— 3229 Mar 22 16 11 NPStyle.c -rw-r—r— 2844 Mar 22 16 11 NPSubmit.c -rw-r—r— 4624 Mar 22 16 11 NPTaskMn.c -rw-r—r— 5576 Mar 22 16 43 NPTextAr.c -rw-r—r-- 4628 Mar 22 16 11 NPTxtFld.c -rw-r—r— 10186 Mar 22 16 11 NaviPres.c -rw-r—r— 48790 Mar 22 16 11 NaviPres.h lrwxrwxrwx 14 Mar 22 18 48 authentc.c -> raw/authentc.c lrwxrwxrwx 11 Mar 22 18 48 bkgnd.c -> raw/bkgnd.c lrwxrwxrwx 14 Mar 22 18 48 callback.c -> raw/callback.c lrwxrwxrwx 14 Mar 22 18 48 callback.h -> raw/callback.h lrwxrwxrwx 13 Mar 22 18 48 chooser.c -> raw/chooser.c lrwxrwxrwx 13 Mar 22 18 48 chooser.h -> raw/chooser.h lrwxrwxrwx 13 Mar 22 18 48 cursors.h -> raw/cursors.h lrwxrwxrwx 13 Mar 22 18 48 destdlg.c -> raw/destdlg.c lrwxrwxrwx 9 Mar 22 18 48 doc.h -> raw/doc.h lrwxrwxrwx 14 Mar 22 18 48 doccache.c -> raw/doccache.c lrwxrwxrwx 13 Mar 22 18 48 docedit.c -> raw/docedit.c lrwxrwxrwx 14 Mar 22 18 48 docgraph.c -> raw/docgraph.c lrwxrwxrwx 14 Mar 22 18 48 docrefer.c -> raw/docrefer.c lrwxrwxrwx 13 Mar 22 18 48 docview.c -> raw/docview.c lrwxrwxrwx 12 Mar 22 18 48 fields.c -> raw/fields.c lrwxrwxrwx 10 Mar 22 18 48 find.c -> raw/find.c lrwxrwxrwx 13 Mar 22 18 48 fldedit.c -> raw/fldedi .c lrwxrwxrwx 10 Mar 22 18 48 func.h -> raw/func.h praaa Sat Mar 25 10:29:33 1995 lrwxrwxrwx help.c -> raw/help.c lrwxrwxrwx historyd.c -> raw/historyd.c lrwxrwxrwx hooksmac.c -> raw/hooksmac.c lrwxrwxrwx hooksmsw.c -> raw/hooksmsw.c lrwxrwxrwx hooksx.c -> raw/hooksx.c lrwxrwxrwx hotlist.c -> raw/hotlist.c lrwxrwxrwx html.c -> raw/html.c lrwxrwxrwx html.h -> raw/html.h lrwxrwxrwx htmlerrs.c -> raw/htmlerrs.c lrwxrwxrwx imgcache.c -> raw/lmgcache.c lrwxrwxrwx mits.c -> raw/imts.c lrwxrwxrwx keymore.h -> raw/keymore.h lrwxrwxrwx linkchck.c -> raw/linkchck.c lrwxrwxrwx makemap.c -> raw/makemap c lrwxrwxrwx navilink.c -> raw/navilink.c lrwxrwxrwx pagcache.c -> raw/pagcache.c lrwxrwxrwx prefs.c -> raw/prefs c lrwxrwxrwx source.c -> raw/source.c -rw-rw-rw- stamp.c lrwxrwxrwx stamper.c -> raw/stamper c lrwxrwxrwx style.h -> raw/style.h lrwxrwxrwx styledlg.c -> raw/styledlg.c lrwxrwxrwx undo.c -> raw/undo.c lrwxrwxrwx undo.h -> raw/undo.h lrwxrwxrwx url.c -> raw/url.c lrwxrwxrwx util.c -> raw/util.c lrwxrwxrwx view.c -> raw/view.c lrwxrwxrwx view.h -> raw/view h lrwxrwxrwx viewcmd.c -> raw/viewcmd.c lrwxrwxrwx viewcol.c -> raw/viewcol.c lrwxrwxrwx viewdraw.c -> raw/viewdraw.c lrwxrwxrwx viewedit.c -> raw/viewedit.c lrwxrwxrwx v ewfrmt.c -> raw/viewfrmt.c lrwxrwxrwx viewms.c -> raw/viewins.c lrwxrwxrwx viewsave.c -> raw/viewsave.c lrwxrwxrwx viewsel.c -> raw/viewsel.c lrwxrwxrwx viewutil.c -> raw/viewutil.c lrwxrwxrwx winmenu.c -> raw/winmenu.c lrwxrwxrwx xvt 3 peg.c -> raw/xvt 3 peg.c lrwxrwxrwx xvtxbm.c -> raw/xvtxb .c lrwxrwxrwx xximt.c -> raw/xximt c Files included for reference- NPChoose.c: interface for local and remote file chooser NPDoc.c: interface for collections NPDocMn.c: interface for collections menu NPNewStl.c: interface for styles NPNvLink.c: interface for autogeneration of links NPPage.c: interface for page window NPPageMn.c: interface for page menu NPStyle.c: interface for styles chooser.c: local remote file system selection callback c: client-server communications 25 10:29:33 1995 3 to implement collections to implement edit functions collections to implement graphing of collections to implement collections to implement collections to implement autogeneration of links to implement styles to implement copy and paste address functions ans writes pages page editing functions nad s.h Sua Fab 26 17:28:01 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ /* " Define symbolic names, constants, and macros */ #ιfndef DMS_H #defιne DMS_H •define DM_0K 1 •define DM_ERR0R 0 #defιne DM_TRUE 1 •define DM_FALSE 0 #defιne DM_END_DATA 2 /* no more data to fetch */ typedef struct ( char "name, int fired; void (*actιon) () ; } DM_Alert, extern void DM_Poll (void) ; extern void DM_H__ndleAlerts (void) , extern int dmSaveError; extern char *dm_lastoιd, extern int dm_Verbose; /* ** DM External api calls */ extern int DM_OpenDB(char "server, char "name, char 'user, char "pass, DM_Alert 'alerts) extern int DM_ReOpenDB(DM_Alert 'alerts) , extern int DM_CloseDB(voιd) , extern int DM_Exec(char 'query); extern int DM_Create (char *tablena e, Ns_Set *forτn) , extern int DM_Update (char *tablename, Ns_Set *form, char *where) ; extern Ns_Set *DM_Selec (char *sql) , extern int DM_GetRow(Ns_Set 'row); extern Ns_Set *DM_ZeroOrOneRow(char *sql, int *nrows), extern Ns_Set *DM_OneRow(char *sql), extern int DM_Flush(voιd) ; extern mt DM_DML (char *sql ) , extern mt DM_DDL (char *sql ) ; extern int DM_Begm (voιd) ; extern mt DM_End (void) ; extern int DM_Abort (void) ; /* ** dm_ are internal DMS helper routines */ extern void dm_panic (char *msg) ; extern void dm_error (char *fmt, ... ) ; extern mt dm_error_pop (char **err) ; extern void dm_error_flush (void) ; extern t dm_StrTrιm (char **strιng) ; typedef struct DM_TableInfo { int ncoluiπns; Ns_Set *'columns; ) DM_TableInfo; extern void DM_InιtTableInfo(voιd) ; extern DM_TableInfo *DM_GetTableInfo(chaι 'table). aadaa.h Su Fab 26 17:28:01 1995 2 •define DM_TableValue(t,k) (Ns_SetGet( (t)->info, ) ) •define DM_TableDescription(t) (DM_TableValue(t, "table_description") ) •define DM_TableName(t) ( (t)->info->name) extern int DM_ColumnIndex(DM_TableInfo 'tinfo, char 'name) ; •define DM__ColumnCount(t) ( (t)->ncolumns) •define DM__ColumnName(t,i) ((i) < 0 ? NULL : (t)---columns[ (i) ] ->name) •define DM_ColumnValue(t,i,k) ( (i) < 0 ? NULL : Nε_SetGe ( (t) ->columns[ (i) ] , ) ) •define DM_ColumnType(t,i) (DM_ColumnValue( (t) , (i) , "colut_ιn_type" ) ) •endif /* DMS_H */ nadefa.h Thu Mar 23 14:10:49 1995 •l ndef NSDEFS. •define NSDEFS. •define NS_R_OK 0 •define NS_W_OK 1 •define NS_OK 1 •define NS_ERROR 0 •define NS_SUCCEED •define NS..FAIL 0 •define NS. TRUE 1 •define NS. .FALSE 0 •define NS. .ON 1 •define NS. .OFF 0 •define NS. .ALLOWED 1 •define NS. .UNAUTHORIZED 2 •define NS. .FORBIDDEN 3 •define NS. .GROWBUFSIZE 512 •define NS. .DSTRING_STATIC_SIZE 200 •define NS. .SQL_BUFSIZE 400 •define NS. MAX_FIELDNAME 64 •define NS_MAXURLSIZE 1024 •define NS__PAGES_SUBDIR "pages " •define NS_DATA_SUBDIR " data " •define NS_ADMIN_USERNAME "nsadmin" •define NS_GRAMMAR_FILE "grammar.dat" •define NS_FREQLEX_FILE "freqlex.dat" •define NS_STOPWORD_FILE "stopword dat' •define NS_OPERATOR "OP" •define NS_SELECT "SELECT" /* Server errors */ •define NS_ERR_INVALIDURL "Invalid URL" •define NS_ERR_NOFORM "Couldn't find form" •define NS_ERR_UNKNOWN_OPERATION "Daemon can't handle operation' •define NS_ERR_MISSING_OPERATION "URL didn't contain an operation" •define NS_ERR_NOSEARCHDATA "No Search data passed m' •define NS_ERR_NOSHFS "No Search Hit format String' •define NS_ERR__NOPAGE "No page submitted' •define NS_ERR_BADFORM "Form data incompatible with this server ' /* Known operations */ •define NS_OP_UrlPre ix "NS" .OP_GetSearchFormPιcker "GetSearchFormPicker" _OP_GetSearchForm "GetSearchForm" _OP_SearchQBF "SearchQBF" _OP_GetLocalHιlιtedPage "GetLHP" _OP_GetRemoteHι1ltedPage "GetRHP" _OP_MoreLιkeThιs "MoreLikeThis" _OP_Navιlιnk "SmartLink" _OP_GetLoadForm "GetLoadForm" _OP_GetEntryForm "GetEntryForm" _OP_GetUpdateForm "GetUpdateForm" _OP_GetUpdateOrEntryForm "GetUpdateOrEntryForm" _OP_InsertRow "InsertRow" _OP_UpdateRow "UpdateRow" _OP__DeleteRow "DeleteRow" _OP_GetCollectιons "GetCollections" _OP_GetMetaTables "GetMetaTables" _OP_Admιn "Admin" nadafa.h Thu Mar 23 14:10:49 1995 •define NS_OP_GetAsset "Asset" •define NS_OP_About "About" •define NS_OP_Permissions "ns_permιssions' •define NS_OP_Cost "ns_costs" •define NS_METHOD_GET "GET" •define NS_METHOD_PUT -PUT" •define NS_METHOD_P0ST "POST" •define Urlθperatιon(urlv) (urlv[l]) •define UrlTable(urlv) (urlv(2]) •define UrlRowId(urlv) (urlv[3] ) •define NS. FORM. .SEPARATOR •define NS FORM. .PREF_KEY "Pref" •define NS..FORM. OPERATOR_KEY "ColOperator" •define NS. FORM. .VALUE_KEY "ColValue" •define NS. FORM. .SELECTED_KEY "ColSelected" •define NS_:FORM. .QINFO_KEY "QueryInfo" •define NS. FORM. .EINFO_KEY "Entrylnfo" •define NS FORM. .ORDERBY_KEY "Or erBy" •define NS. FORM. .ORDERBY_NONE_KEY " (no ordering) " /* Visible to user' •define NS. FORM. DISTINCT_KEY "Distinct" •define NS. FORM. IFT_KEY "IndexFullText" •define NS. FORM. .ROWID_KEY RowID" •define NS. FORM. .COLLVALUE_KEY CollectionValue" •define NS. FORM. .COLLOPERATOR_KEY "CollectionOperator" •define NS. FORM. .URL_KEY "Url" •define NS. FORM. .HIDE_KEY "Hide" •define NS. FORM. .TIME_KEY "time" •define NS. FORM. .AMPM_KEY "amp " •define NS. FORM. .AM "AM" •define NS. FORM. .PM "PM" •define NS. FORM. YEAR_KEY "year" •define NS_:FORM. .MONTH_KEY "month" •define NS. FORM. .DAY_KEY "day" •define NS_COLLECTIONS_TYPE "text/x-ns-collection-lis " •define NS_KEY_FIELD "Old" •define NS_CONFIG_TABLE "ns_confιg" •define NS_PREFS_TABLE "ns_preferences" •define NS_URL_COLUMN "ns_url" •define NS_BODY_COLUMN "ns_body" •define NS_TITLE_COLUMN "ns_tιtle" •define NS_FIRSTTERM "NSFIRSTTERM" /* hash table stuff */ •ifndef _CLIENTDATA # ifdef STDC typedef void 'ClientData,- # else typedef int 'ClientData; # endif /* STDC */ •define _CLIENTDATA •endif •define NS_SMALL_HASH_TABLE 4 /' * Acceptable key types for hash tables: nadefa.h Thu Mar 23 14:10:49 1995 •define NS_STRING_KEYS 0 •define NS_0NE_W0RD_KEYS 1 •define NS_HTMLTAG_TYPE_SELECTSQL "SELECTSQL" •define NS_HTMLTAG_TYPE_SELECTSQLORNULL "SELECTSQLORNUL " •define NS_HTMLTAG_TYPE_SELECT "SELECT" •define NS__HTMLTAG_TYPE_SELECTORNULL "SELECTORNULL" •define NS_HTMLTAG_TYPE_RADIO "RADIO" •define NS_HTMLTAG_TYPE_RADIOORNULL "RADIOORNULL" •define NS_HTMLTAG_TYPE_TEXTAREA "TEXTAREA" •define NS_HTMLTAG_TYPE_INPUT "INPUT" •define NS_HTMLTAG_TYPE_AUTOINCR "AUTOINCR" •define NS_ASSET_RULE "rule.gif" •define NS_ASSET_BULLET "bullet.gif" •define NS_ASSET_SEARCH_FORM_HEADER "SearchFormHeade .g f" •define NS_ASSET_ENTRY_FORM_HEADER "EntryFormHeader.gif" •define NS_ASSET_UPDATE_FORM_HEADER "UpdateFormHeader.gif •define NS_ASSET_SEARCH_RESULTS_HEADER "SearchResultsHeader.gif" •define NS_ASSET_SEARCHlFORM_HELP "SearchFormHelp.html" •define NS_ASSET_METADATA_HEADER "MetadataHeader.gif" ♦define NS_ASSET_SEARCHABLE_TABLES "SearchableTables.gif" •define NS__RULE "<IMG SRC=\"/NS/Asset/" NS_ASSET_RULE "\">" •define NS..BULLET "<IMG SRC=\"/NS/Asset/" NS_ASSET_BULLET "\" ALIGN=Mιddle>' •endif /* NSDEFS H */ crud.h ua Mar 7 17:59:44 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved */ •ifndef CRUD_H •define CRUD_H •ifdef cplusplus extern "C" { •endif •include "auth.h' •include "for .h" •define Ns_Connectιon Crud typedef struct desc { Auth *auth. Form 'form, ) Desc, typedef enum {C, R, U, D, X, B) crudtype, typedef struct crud { /* internals */ struct crud 'next, *prev /* crud stuff */ crudtype type, Auth 'auth, char *url, char 'method, char 'queryString, char 'protocol, Form 'form, /* input strand id */ /* output callback */ mt Cfunc) (void * int) , int ('part) (void *, mt) void *ctx /* comm context */ void 'comm char status[0x100] , long since /* date for reload */ int abort 1 int info 1 /* only want strand fo */ int reload 1 /* check if newer than cache */ int navisoft 1, /* connected to NaviSoftware */ char *refered_by, /* Url (or comment) of where we came from*/ } Crud, •define CrudUrl(c) (c->url '= NULL ~ c->url c->form->URL) /* * create forms, append fields to them, and delete them * - all char "s are copied */ /* form the description */ Crud *CreateCrud(char *url, Desc 'desc, t sid); Crud *UpdateCrud(char *url, Desc 'desc, mt sid), /* delete w/ default authorization */ Crud 'DeleteCrudlchar *url), /* if URL is given, GET url crud.h Tua Mar 7 17:59:44 1995 2 otherwise use Form to build a request for HTTP: <ISINDEX> -> RetrieveCrudC" , [url / GET / {: "search string"}]) <IMG ISMAP> -> RetrieveCrudC", [url / GET / _:"x,y"}]) <INPUT TYPE="SUBMIT"> -> RetrieveCrudC", [url / GET|POST / {name:value ...}]) for Others: define form mapping? */ Crud *RetrieveCrud(char *url, Form 'form) ; /* 'browse' the url... nonstandard, for our choosers */ Crud 'BrowseCrudlchar *url) ; QueueCrud: start the I/O for this crud, frees on completion calls funcfctx,sid) on completion SyncCrud: force a crud to complete, frees storage aborts if func(ctx) returns non-zero returns "succes" of operation??? AbortCrud: abort a crud, frees storage returns false if crud already complete ' / Crud 'QueueCrud(Crud 'crud, int ('func)lvoid *,int), void *ctx) ; int SyncCrud(Crud 'crud, int (*func)(void *), void *ctx) ; int AbortCrud(Crud *crud) ; void CrudRundown(void) ; /* wait for all outstanding cruds */ /* for command-line type programs -- run the cruds that have been queued */ ' void RunCruds(int verbose) ; •ifdef cplusplus } •endif •endif nlpatructa.h Tu« Jan 31 12:41:13 1995 1 •ifndef NLPSTRUCTS_H •define NLPSTRUCTS_H /* Copyright 1994-1995 NaviSoft, Inc All rights reserved. */ /* nlpstructs.h Definitions for nip structures and Routines for allocating, deallocating, and printing out these structures */ /* Structure definitions */ typedef struct backpointer { /* HTML-specific */ mt StartPnum; t EndPnum, ~ Para 'para, /* for starting pnum */ int StartOffset; int EndOffset; } BackPointer; typedef struct token { char 'string, char 'stem, BackPointer *bp; int pos; ) Token; •define SENTENCE 0 •define SECTION 1 /* Express is deterministic today No ambiguity is preserved. We'll start preserving it when we have good ways of actually resolving it. */ typedef struct express { List 'lexical; /* Just stemmed, non-overlapping tokens with POS. * We'll move to registers, and maybe some pattern * matching when we need to. */ List 'syntactic; /* Current version 3 ust lists of tokens; * We'll move to real trees when we need to */ /* Semantic and ResolvedSemantic will be added later */ } Express; typedef struct textob 3 { /* Superclass of Sentence and Section */ t type; BackPointer *bp; Express 'express; /* Only sentences */ List 'title; /* Only sections have titles */ List 'sub; /* Only sections have sub textob 3 s */ } Textob 3 ,- / .... * .. * .. * , ** .. *** ... ** • **** . * ......... * ..• * •./ /* Memory allocation and deallocation stuff for structures: */ Textob 3 ' 'NewSection() ,- Textob 3 'NewSentence() ; void FreeTextob} (Textob 3 *textob 3 ); Express 'NewExpress (List 'tokens, List 'phrases) , nlpatrαeta.b Tuβ Jan 31 12:41:13 1995 2 void FreeExpress (Express 'express); void FreeLexicalExpress (Express 'express); void FreeSyntacticExpress (Express 'express); void FreeNg (List *ng) ; Token 'NewToken (char 'string, BackPointer *bp) ; void FreeToken (Token 'token) ; BackPointer 'NewBackPointer(int startpnum, int endpnum. Para 'para. int startoffset, int endoffset) ; void FreeBackPointer (BackPointer *) ; /A*************************************************************** / /* Printing routines for structure: */ /.... ** »• ** • * . ** • ** . * . * * **** . *** . ************ ... ** .... ** . * ..... * ./ Token 'PrintTokenLong (Token 'token) ; Token 'PrintTokenShort (Token 'token) ; List 'PrintTokensShort (List 'tokens) ; BackPointer 'PrintBP (BackPointer *bp) ; Textobj 'PrintTextobj (Textobj 'textobj, int in) ; Textobj 'PrintSection (Textobj 'textobj, int in) ; Textobj 'PrintSentence(Textobj 'textobj, int in) ; void indent(int n) ; int NgPnum(List *ng) ; int NgStart(List *ng) ; int NgLengthtList *ng) ; •endif /'NLPSTRUCTS H*/ nabtal.b Wad Fab 8 18:20:36 1995 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •ifndef HTML_H •define HTML_H •ifdef cplusplus extern "C" { •endif /* Structuring tags */ •define HTML_TAG 0x0 /* Encloses all HTML documents */ •define BODY_TAG 0x1 /* Encloses the interesting stuff */ •define HEAD_TAG 0x2 /* Encloses the header */ •define PLAINTEXT_TAG 0x3 /* Everything after this is literal */ /* Header tags */ •define HEAD_START 0x10 •define ISINDEX_TAG 0x10 /* Searchable document */ •define LINK_TAG 0x11 /* Standard link, not clearly defined*/ •define BASE_TAG 0x12 /* original version of doc, resolves relative URLs */ •define META_TAG 0x13 /* To be included in HTTP header */ •define TITLE_TAG 0x14 /* Title of doc */ •define NEX ID_TAG 0x16 /* Eh? */ /* experimental — •define REFRESH_TAG 0x15 /' live feed refresh */ / « experimental -- •define HEAD_END 0x16 /* Comment tag, I believe this is depreciated */ •define COMMENT TAG 0x20 /* Encloses a comment nabtal.h Wad Fab 8 18:20:36 1995 /* Formating tags */ ♦define BR_TAG •define NOBR_TAG •define WBR_TAG •define CENTER_TAG •define FONT_TAG •define BASEFONT_TAG •define HR_TAG /* Style tags */ •define STYLE_START •define B_TAG •define CITE_TAG •define CODE_TAG •define DFN_TAG •define EM_TAG •define I_TAG •define KBD_TAG •define SAMP_TAG •define STRONG_TAG •define SUB_TAG •define SUP_TAG •define TT_TAG •define U_TAG •define VAR_TAG •define XMP_TAG •define STYLE_E_TO /* Things inside of forms */ •define INPUT_TAG •define TEXTAREA TAG •define SELECT_TAG •define OPTION_TAG /* HTML + Tags */ •define EMPH_TAG HTML+ Generic emphasis */ •define EMBED_TAG Contents passed to filter determined by TYPE at tr (MIME) */ •define SP_TAG Unbreakable space */ •define FIG_TAG Figure, takes SRC */ •define FIGA_TAG Figure anchor * / ♦define ICON_TAG Small graphics' takes src */ •define TBL_TAG Table: tt, th, td */ •define PANEL_TAG Floating panel of text */ •define GROUP_TAG Hierarchical grouping */ /* End Tag */ •define END_TAG Oxfd Ends a nested entity */ /* Unknown Tag */ •define UNKNOWN_TAG Oxfe /* Error Tag */ •define ERROR_TAG Oxff •define HTML_MARK ' \177' /* Mark indicating a tag */ •define HTML_LEN_LOW •define HTML_LEN_HIGH •define HTML_POS_TAG •define HTML_END_TAG •define HTML_ERROR_HIGH •define HTML_ERROR_LOW •define HTML_ERROR_ARG nabtal.h Wad Fab 8 18:20:36 1995 3 •define HTML_HEAD_LEN 4 /* Not included in len */ •define HTML_END_LEN 5 /* The len of an END_TAG is always 1 */ •define HTML_ERROR_LEN 7 /* The len of an ERROR is always 3 */ /* HTML_MARK, 2 bytes of size, 1 byte of tag, random data */ /* Attributes structure for the various tags */ •define VAL_NONE 0 •define VAL_STR 1 •define VAL_NUM 2 struct attribs { char 'name; unsigned int value: 2; unsigned int present: 1; short len; char *val ; ); /* Structures to contain latinl character to name mappings */ struct chartab { char 'name; int ch; in¬ struct unknownchar ab { int ch; char *str; ); /* Structures for the html page */ typedef struct para { struct para 'post; struct para *parent; struct para *first; char *text; short tlen, tmax; char *tagtext; short pnu ; /* Paragraph number within page */ unsigned char tag; unsigned int isindex: 1; /* Is this FORM auto generated from an ISINDEX*/ unsigned int fake: 1; /* Psuedo para inside preformatted text */ ) Para; typedef struct htmlpage { char *url; /* URL for this page, may be a local filename */ char *docname; /* URL of document containing us */ char 'title; char 'style; /* URL for style sheet */ char *upl; /* URL's for standard links */ char *uptit; /* Titles for standard links */ char "otherlinks; /* contents of non-standard links */ char *base; /* URL for BASE (whatever) */ char "headerinfo; /* Any stuff we did not understand */ short 'headererrs; /* Any errors */ char 'headerargs; /* Errors argument */ short 'trailerrs; /* Any after text? */ char 'trailargs; unsigned int isindex: 1; unsigned int haderrors : 1; unsigned int mcomextensions : 1; Para 'first; char' 'iiprompt; /* prompt string for header isindex tag */ /* experimental */ long refresh; /* live feed refresh */ /* experimental */ } HtmlPage; nahtml.h Wad Fab 8 18:20:36 1995 & followed by invalid escape sequence */ A termination tag had attributes */ A termination tag did not match the opening tag An EOF was read before the closing > */ ' An attribute was given to a tag which has none A bad attribute was given to a tag */ No closing quote for an attribute's value */ No value given for attribute that needs one */ Value given for attribute that shouldn't have o Body item found in header */ Header item found in body */ Characters found after page end */ Some tags not closed */ Tag within a title tag */ HEAD, BODY, or HTML tag found inside BODY */ Unknown HTML tag found */ Paragraph too big */ typedef struct nestinfo { unsigned char 'nesting, /* tags of all nested things */ unsigned char "tagtext, /* text associated with 'em */ short ncnt, nmax; } Nestinfo, "* external defn's •/ /* stream functions */ typedef struct { mt state; FILE *fp, } textblob, extern int text2html(textblob *), extern t parse_flie(FILE *), extern int parse_strιng(char **), extern HtmlPage *FιllHtmlPage(HtmlPage *, mt(*) (voιd *), void *), extern WπteHtmlPage(HtmlPage *, int, ιnt(*)(voιd *,ιnt), void *), extern WriteHtmlBodyfHtmlPage *, int(*) (void *,ιnt), void *), extern void KillHtmlPage(HtmlPage *); •ifndef PROTOTYPE ♦define PROTOTYPE(x) x •endif •ifndef XVT_CALLCONVl •define XVT_CALLC0NV1 •endif /* Exported routines */ /* lhtml.c */ extern void XVT_CAI_LC0NV1 itcharnames PROTOTYPE! (void) ) ; extern void XVT_CALLCONVl cleanupparser PROTOTYPE( (void) ) ; extern mt XVT_CALLC0NV1 HtmlPage2Fιle PROTOTYPE! (struct htmlpage *,char ',ιnt)l extern char * XVT_CAI_LC0NV1 HtmlPage2Str PROTOTYPE! (struct htmlpage *, int )); extern int XVT_CALLCONVl HtmlPage2URL PROTOTYPE( (struct htmlpage *,char *)), extern int XVT_CALLCONVl ParaPreformatted PROTOTYPE( (struct para *)), extern void XVT_CALLCONVl ParaListFree PROTOTYPE! (struct para *)), extern int HTML_AttrValue( t tag, char *name) , extern t _HTML_HasAttr(char *str,ιnt len,int tag,char *output, t osize.char 'name) extern mt XVT_CALLC0NV1 HTML_HasAttr PROTOTYPE((char *,char *,mt,char *)); extern mt XVT_CALLC0NV1 HTML_HasAttrStι PROTOTYPE! (char *,in ,char *, int,char *)>; nabtml.h Wad Fab 8 18:20:36 1995 5 extern struct attribs * XVT_CALLC0NV1 HTML_GetAttrs PROTOTYPE) (char *)); extern char * XVT_CALLC0NV1 TagSkipToEnd PROTOTYPE( (char *) ) ; extern int XVT_CALLC0NV1 TagHasWidth PROTOTYPE( (char *) ) ; extern int XVT_CALLCONVl TaglsField PROTOTYPE) (char *)); extern int XVT_CALLC0NV1 TagLen PROTOTYPE((char *)); extern int XVT_CALLCONVl Taglncr PROTOTYPE((char *)); extern char * XVT_CALLCONVl TagGetName PROTOTYPE( (in ) ) ; extern int XVT_CALLCONVl TagNeedsTerminator PROTOTYPE( (int) ) ; extern int XVT_CALLCONVl TaglsPara PROTOTYPE((int)) ; extern char * XVT_CALLCONVl HTML_last PROTOTYPE((char *)); extern int XVT_CALLCONVl HTML_len PROTOTYPE((char *) ) ; extern int XVT_CALLCONVl HTML_tag PROTOTYPE((char *) ) ; extern int XVT_CALLCONVl HTML_plain PROTOTYPE( (char *) ) ; extern int XVT_CALLC0NV1 HTML_matched PROTOTYPE((char *,int)); extern void XVT_CALLCONVl HTML_FillTag(char *buf, int tag); extern void XVT_CALLCONVl HTML_FillEndTag(char *buf, int tag) ,- extern struct chartab *XVT_CALLCONVl HTML_charnames PROTOTYPE( (void) ) ; extern char * LatinlCharNa e PROTOTYPE((int)) ; extern char * local21atinl (char *); extern char * latinl21ocal(char *); extern void XVT_CALLCONVl _FindNesting PROTOTYPE( (struct para *,int,struct nestinfo *)), extern void XVT_CALLCONVl FindNesting PROTOTYPE) (struct para *,int,struct nestinfo *)); extern int XVT_CALLCONVl TagActive PROTOTYPE! (struct para *,int,int tag)); •ifdef cplusplus } •endif •endif /* HTML H */ •tr.b Tbu Fab 16 17:56:54 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •ifndef STRAND_H •define STRAND_H •include <stdio.h> •include <stdarg.h> •if defined(THINK_C) | | defιned(THINK_CPLUS) # include <Types.h> #else # include <sys/types.h> •endif •include <tιme.h> /* metadata about a strand.. */ struct strandinfo { int status; const char 'type; unsigned long size; tιme_t date, /* when we got it */ tιme_t lastmod; /* could be a file */ tιme_t expires, mt modifyable : 1; int naviserver : 1; const char 'document; ); /' a fake type for the "C" interfaces */ struct cstr; •lfdef cplusplus typedef enum {mem, disk, web, info) loc; tιme_t fudge(tιme_t,tιme_t) , // figure a reasonable expiration given lastmod class strand { static int nextserno; static strand *sιds; static strand *caches; void remlist() ; void addlist(strand "); void expire() ; int serial; protected: int status; char *type; unsigned long size; tιme_t date; // when we got it tιme_t lastmod; // maybe lt.s a file tιme_t expires; mt modifyable : 1; int naviserver : 1; char 'document; loc from, current; int refcnt, dirty, char 'storage; char 'filename; char *url; strand "list; // what list are we on ■tr.b Tbu Fab 16 17:56:54 1995 2 strand 'next, char 'cacheurl; // what url it is under in the cache void 'cachebrand; strand(strandmfo *, loc) ,- -strand!) ; int gensid)) , static strand 'cachedfchar *, void *); public. /* GWW */ static strand 'fιnd(mt) ; protected void addref() ; void delref() ; void *ctx, friend class lostrand, friend class rstrand, friend class wstrand, public: inline mt serno!) { return(serial) , ) inline tιme_t expireat() { retur (expires ' expires (lastmod ' fudge(lastmod,date) • date)); }, static void reaper)), static int flush(char *); static mt cache(int, char *, void *) ; static t checkfor(char *, void *, int) ; }; extern "C" { •endif void CacheReap() ; int CacheFlush(char *); int CacheCheckFor(char *, void *, mt ) int ValιdInCache(char *); •ifdef cplusplus ) class lostrand { protected: int valid; strand *s; unsigned long cur, max, FILE *fp; void open(strand *); public: lostrand() ; -lostrand)) ; void ιorewιnd() ; void close(mt); inline mt operatorDO ( return valid; ); ime int status)) { return s->status; ); inline const char 'type)) { return s->type; }; inline unsigned long size)) { return s->sιze; }; inline tιme_t date)) { return s->date; ); ime tιme_t lastmod)) { return s->lastmod; ); str.b Tbu Fab 16 17:56:54 1995 3 mime tιme_t expires!) { return (s->expιreat( ) ) ; ) inline mt modifyable!) { return s->modιfyable; ) inline int naviserver!) { return s->navιserver, ) inline const char 'document!) { return s->document, inline int serial() { return s->serno(), ) class rstrand ■ public lostrand char *url. public rstrand() , -rstrand() ; int opentchar *), // only cached stuff long available() , mt read(char *, int), int getline(char *,ιnt), char 'tofileO , void 'context(); void close(void *); }, extern "C" { •endif struct cstr * RsOpenCache(char *, struct strandmfo *) struct cstr * RsOpenlddnt, struct strandinfo *) , int RsReadC(struct cstr*), int RsReadBuf(struct cstr*, char *, int), int RsGetLιne(struct cstr*, char *, t) , void RsRewmdlstruct cstr*), int RsFillFile(struct cstr*, FILE *), char *RsForceFιle(struct cstr*), void *RsContext(struct cstr*), void RsCloseWCtxtstruct cstr*, void *), void RsClose(struct cstr*), int Rsldtstruct cstr *), •ifdef cplusplus } class wstrand : public lostrand { void overflow(long) , public: -wstrand() ; int create(int, const char *); int create(strandinfo *, loc), nt write(char), int write(char *) ; int wrιte(char *, int) ; int print(char *, ... ) ,- nt vprintlchar *, va_lιst) , mt file(FILE *) , int ιnfo() , t snapshot() , t close)) , void forget() ,- •tr.h Tbu Fab 16 17:56:54 1995 4 }; extern "C" { ♦endif struct cstr* WsCreateϋnt, const char *) ; struct cstr* WsCreatelnfo(struct strandinfo *); int WsPutC(struct cstr*, int); int WsPutStr(struct cstr*, char *) ; int WsPutBuf(struct cstr*, char *, int) ; int WsPrint(struct cstr*, char *, ...); int WsPutFile(struct cstr*, FILE *),- int WsClose(struct cstr*); void WsForget(struct cstr*); int _info(char *,...); •ifdef cplusplus } ♦endif •endif taak.b Tαa Jan 31 12:41:14 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •ifndef TASK_H •define TASK_H •ifdef cplusplus class task { task *par, *sib, 'son; protected: finish(int = 0) ; run(int = 0) ; block(int = 0) ; public: int state; void 'pstate; int ready : 1; int prog : 1; int done : 1; static task 'root; task(task *) ; virtual -task)); int tickle() ; task 'iterate(int (*) (void *, task *), void *) ; virtual int partial() ; virtual int complete() ; }; class ctask : public task { void *ctx; int ('part) (void *) ; int Ccπrplt) (void *) ; public: ctask(void *, int, int (*)(void *), int (*)(void *)); -ctask() ; int partial() ; int complete() ; }; extern "C" { •endif void AddTaskSeeCrudsRun(void *, int) ; void AddTask(void *, int, int CMvoid *), int (*)(void *)) int RunTasks() ; •ifdef cplusplus }; •endif •endif callback.h Bon Mar 20 13:47:49 1995 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. •ifndef CALLBACK_H •define CALLBACK_H •include "view.h" •include "style.h" •include "crud.h" •include "prefetch.h" typedef struct _forπ_ctx { View 'view; Form 'form; char *url,- char 'origurl; char *anchor; /* Location within page */ Image *image; STYLE *sheet; char *toname; /* For copying */ struct document *doc; /* For copying */ void *codec; /* for decoding inlines */ struct cstr *rs; unsigned int noshow: 1; /* Should we create a view or just cache it? */ unsigned int newview: 1; /* Create a new view even if we've got one */ unsigned int toclip: 1; /* Save content type */ unsigned int fromclip: 1; /* Use saved content type */ int open_type; /* See OPEN_* below. Open dialogue let's us */ /* specify disposal directly */ ) formetx; struct savectx { Page 'page; char *url; View 'view; Form 'form; struct cstr *rs; unsigned int dobase : 1; unsigned int navilink }; struct docsavectx { char *url; struct document *doc; struct cstr 'rs; }; struct copyctx { struct cstr *rs; /* Strand to copy */ struct document doc; /* Once copied, update this doc */ char 'toname; /* URL we think we are writing to */ char *url; /* Actual relocated url */ char *oldtype; /* si.type for rs above */ View *view; }; struct browsectx { char *url; WINDOW w; }; int form_callback(void *vctx, int rid) ; int pagei.callback(void *vctx, int rid) ,- int copycallbacktvoid *vctx, int rid) ,- int pagesaveback(void *vctx, int rid) ; int docsavebacktvoid *vctx, int rid) ; int image_callback(void *vctx, int rid); callback. Mon Mar 20 13:47:49 1995 int _SyncCrud(Crud *); •define 0PEN_DEFAULT 0 •define OPEN_HTML 1 •define OPEN_TEXT 2 •define OPEN_DOCUMENT 3 •define OPEN_SAVE 4 •define OPEN_FILTERS 5 /* And higher */ •endif CALLBACK_H doc.h Mon Mar 13 12:59:04 1995 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved struct docpartlmk; typedef struct docpart { struct docpart 'another, char 'relurl, char 'title; char 'contenttype; struct docpart 'up; struct docpart 'style; struct docpart 'beside; struct docpartlmk *refers_to; struct docpartlmk *refered_by; Links && styles */ struct docpartlmk *downs; All pages we are UP-to RCT bb, tbb; short as; short sublen; short level, unsigned int userplaced: 1; unsigned t levelassigned: 1; unsigned int besided: 1; already used in the beside list */ unsigned t existsr 1,- Someone might link to it without it existing */ unsigned int external. 1; Not part of document, we have a down link none- the-less */ unsigned int needsplac g: 1; unsigned int needsdrawing: 1; unsigned int upneedsdrawing: 1, unsigned mt styleneedsdraw g: unsigned t out_of_date- 1, unsigned mt hidden: 1- unsigned int upboth: 1; struct page 'loaded; /* Not everything can have a page */ double angle, ) DocPart; typedef struct docpartl k { struct docpart *page; struct docpartlmk *next; unsigned mt from_lιst. 1; unsigned int mlιned_ιmage 1, unsigned int bothways: 1, unsigned int formlink 1, unsigned int toexternal• 1, unsigned int needsdrawing: 1; unsigned int ticked: 1; unsigned mt upboth: 1; ) DocPartLink; typedef struct document { char *name; /* Directory name, or url */ char *tιtle; /* not used */ DocPart *fιrst, *last; enum graph_type graph_type; unsigned mt dirty: 1, unsigned mt modifyable: 1; unsigned mt new: 1; unsigned mt askedfordelete ■ 1 unsigned mt anydirt: 1; unsigned int saveasdon : 1; unsigned int savesucceded: 1; unsigned int loadsucceded: 1; char *style; char 'template; enum f11ena_me_type nametype; doc.b Mon Mar 13 12:59:04 1995 2 struct docview 'docview; struct document 'next; ) Documen ; typedef struct docview { int tag,- WINDOW w; WINDOW pane; WINDOW refers_to; WINDOW referenced_by; int width, height; /' Of the window */ Document *doc; DocPart 'externals; DocPart **levels; DocPart "levelnext; int *levelcnt; int *levelradius; short curl, maxl; DocPart 'unattached; int unattachedcnt; int totwidth, totheight; int o ftop, of left; /* these are screen pixels short reduction, expansion; DocPart 'selected; DocPart 'undercursor; unsigned int windowmenu_dirty : 1; unsigned int mousedown : 1; unsigned int dragging : 1; unsigned int drag_out : 1; short int off_x, off_y; /* in screen coords */ short clickcnt; PNT press_pnt; int stop_state; WINDOW stat; /* Let's do our own status bar */ char stat_text [200] ; ) DocView; chooser.h Wad Fab 22 15:50:59 1995 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved. •include "crud.h" struct chooserinfo { mt pro_npt_rιd; char *name; int size; mt chooser_type; int (*func)(voιd ,char *,struct chooserinfo *) ; void *ctx; /* Usually a view/docview, but a WINDOW for NEWWEB,STYLE */ /* and a mapmfo * for MAPLINK int _as_type; /* For openas/saveas */ unsigned mt first_browse : 1; unsigned int second_browse : 1; unsigned int saveimages : 2; /* Needs to be 2 */ unsigned int fullurl : 1; unsigned int fullurlobserved unsigned int locked : 1; /* no functional data */ unsigned int enabled : 2; /* Default button is enabled unsigned int looks_lιke_dιr : 2, unsigned int desktop : 1, /* we're on the Mac desktop * unsigned t inm iweb • 1; Crud *crud; WINDOW w; }; •define CHOOSER. .OPEN •define CHOOSER. DELETE •define CHOOSER. IMPORT •define CHOOSER. SAVEPG •define CHOOSER. SAVEMW •define CHOOSER. .IMAGE •define CHOOSER. LINK •define CHOOSER. NEWWEB •define CHOOSER. .STYLE 8 •define CHOOSER. .MAPLINK 9 •define CHOOSER. WEBIZER 10 •tyla.b Wad Fab 22 14:47:38 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved. */ •ifndef Lιst_Repeat /* Order here is important, change (s,p,e)names arrays in styledlg.c */ enum para_type { P_Normal, P_H1, P_H2, P_H3, P_H4, P_H5, P_H6, P_BlockQuote, P_Pre, P_Lιstmg, P_Address, P__Max ), enum emph_type { EM_B, EM_I, EM_U, EM_TT, EM_Cιte, EM_Code, EM_Defιnιtlon, EM_Em, EM_KBD, EM_Samp, EM_Strong, EM_Sub, EM_Sup, EM_Var, EM_Anchor, EM_CachedAnchor, EM_AnchorPoint, EM_Max ), enum 3 ust_type { J_Left, J_Center, J_Rιgh , J_Fιlled ), enum bullet_type { B_FC, B_FS, B_OC, B_OS, B_GIF }, enum numeral_type { N_Arab, N__SRoman, N_CRoman, N_SLetter, N_CLetter ), •define Lιst_Repeat 4 typedef struct style ( char 'name, /* Should be an absolute URL */ unsigned mt ιs_url.1, struct p_style ( XVT_FNTID fid, int mιt__lead, /* in points */ t indent, sub_ιndent, /* in points */ enum 3 ust_type 3 ust, char 'colour, ) paras[P_Max] ; struct e_style { XVT_FONT_STYLE_MASK style_mask, XVT_FNTID fid; cnar 'colour; ) emphs[EM_Max] , enum nuπveral_type lιst_nums[Lιst_Repeat] struct { enum bullet_type bullet, char *gιf_name, struct image 'image, } lιst_bullets[Lιst_Repeat] , mt lιst_mdent, lιst_sub, lιst__lead, mtralιst_lead, short prehr_poιnts, posthr_poιnts, char *hr_gιf_name, struct image *hr_gιf; unsigned mt modified 1, unsigned int tempmod. 1, unsigned mt cansave: 1, unsigned int readstarted 1, unsigned mt canceled. 1, unsigned int fontwarned 1, struct style 'next, ) STYLE, extern STYLE 'current, *defstyle, 'normalstyle, •endif ▼iβ .h MOD Mar 20 14:40:45 1995 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •ifndef VIEW_H •define VIEW_H •include "html.h" •include "style.h" ♦include "func.h" struct radinfo { t israd, struct view *vιew; ), typedef struct wιndow_ιnfo /* Information associated with the window */ /* which does not change with the view */ /* Currently a bunch of modeless dialogues */ /* associated with a window */ mt current; /* Current hotlist for this view */ WINDOW fmd_rpl, /* Search and replace for the window */ WINDOW form; /* Window for making a form '/ WINDOW radio, /* Radio button window */ WINDOW checkbox, WINDOW reset; WINDOW submit; WINDOW textfield; WINDOW password; WINDOW textarea; /' This is a window, not a dialogue because I need to put WINDOW selectfield; char *selflddata; ' submit & reset don't get windows. They are too simple and there can only 1 be one of each in a form'' H m maybe not */ WINDOW imagefield; Specify an image as a form element */ WINDOW image; Specify an image not as a form element • / WINDOW link; Specify a link. */ WINDOW errors; HTML error window */ WINDOW links; Dangling link window */ WINDOW nvlink, Navilinks dialogue */ WINDOW mapmaker; Map maker dialogue */ WINDOW source, view source */ WINDOW palet,- Field palet */ unsigned mt wasactive:1; unsigned mt was_ιn_form: 1 unsigned mt was_show_form: 1; unsigned int ιcon_changed: 1, unsigned int linkchanging: 1; unsigned int selallenabled: 1; struct _formctx *ρendmg_context; struct view *pendmg_forwards; struct view *restore_vιew; long pendιng_ιd; /* timer for links */ short old_lιst, old_head short old_dl, old_nf; short old_cu; short old_para; int stop__state; /* Stop button state */ long emph_mask; XVT_PIXMAP pmap; } Wlπfo; typedef struct image { struct image 'next; /* Images are all linked together */ char *url; /* Original url of the image */ char *cachename; /* Local filename, if url not local */ vi w.b Mon Mar 20 14:40:45 1995 XVT_IMAGE image; /* display-able format */ unsigned mt ιs_error :1; /* Is a built- image, don't free it */ unsigned int readin :1; /* On first showing a page, don't load images */ unsigned int readstarted :1,/* We've asked for it, but it hasn't come back */ unsiςrned t reload :1, /* we want to read it n */ unsigned t ticked :1; /* Does anyone look at this image now' */ mt unused_cnt; /* Number of passes through ImageCachePurge that image unu sed */ } Image; typedef struct vfield { Note: textarea's are not controls. The window given here is a private child*/ window of the pane, to find the textarea itself (a tx) xvt_vob 3 _get_data */ WINDOW id; short cid; /* control Id used by event handler */ long x,y; /* absolute, position in infinite window, no sb*/ short width,height; short baseline,lead; short maxlen, /* XVT does not support this, we must do it */ short vmax; /* Max of password field */ char 'passwordvalue; /* Value of a password field */ char *name 'value; /* Means for identifying which */ Image 'ima ie, enum f_tv > .e type, realtype; /* Realtype is only meaningful when printing */ XVT_IMACE prtr_image; /* Only meaningful when printing */ Para 'para, /* Paragraph in which defined */ int o fset; /* Offset within para at which defined */ unsigned mt ismap :1, /* The image is a ismap image ( f in anchor) */ unsigned int stub :1, /* The image has not been read in yet */ unsigned int ticked :1, /* The image has been positioned */ unsigned t floatleft :1, /* The image is to float to the left margin */ unsigned int floatright /* The image is to float to the right margin */ enum lalign { ιa_top, ιa_center, ιa_bottom ) ιmage_alιgn; short border width; short vsp, hsp; /* Space around image */ XVT_FONT_STYLE_MASK anchor; /* Is image m anchor' */ struct vfield 'nextfloat; /* Next floating image pending positioning */ } VField, typedef struct vpara { struct vpara *post, 'parent. Para 'para; struct vpara 'subs; char "lines; /* Line breaks in current view */ /* lines[0]==para->text */ short 'lheight; /* vertical pos of each line */ /* topmost pixel of the line */ max ascent */ max descent */ total text width */ word count */ size of the lines array */ Height of paragraph */ Vertical position of start of paragraph */ initial and subsequent indents */ Initial leading */ Justification of this paragraph */ Any fields in the current form */ These guys need to be positioned at eol */ Last number in ordered list */ vi w.h Mon Mar 20 14 :40 :45 1995 ) VPara ; typedef struct linklist { NRCT pos ; char 'name ; char Oπgname; Para 'para; /* Paragraph in which defined */ short offset; /* Offset within para at which defined */ unsigned int image:1; /* This is an unloaded image, not a real link */ unsigned int ιnlιst:l; /* This is an unloaded image, not a real link */ } LmkList; typedef struct anchorlist { char 'name; long y; Para 'para; /* Paragraph in which defined */ int offset; /* Offset within para at which defined */ } AnchorList; typedef struct position { int offset; unsigned int mapped: 1, /* If we are on the edge of a field, the field's window wi /* If a Selectιon=> no selection /* If a Selectιon=> not drawn */ Document location (needs to have scroll bar off subtracted ) */ maximum ascent & descent for line */ ascent & descent of font */ typedef struct selection { Position start; Position end; ) Selection; typedef struct redrawmfo { short offset; } Redrawlnfo; typedef struct view { int tag; WINDOW w; WINDOW pane; /* pane or pixmap WINDOW truepane; /* always the pane '/ WInfo 'winfo; struct view *nextsame; /* Next v ew looking at same page */ Page 'page; /* Page we are looking at */ VPara *fιrst; /* Paragraph list, divided into lines struct view *back, *fore; short wwidth, wheight; short hres, vres; short hfact, vfact; long text_height, text_offtop; long text_wιdth, text_offleft; long text_overhead; /* when printing, this space needed for title '/ struct style *sheet; /* This reflects the current state of the drawing process */ XVT_FNTID 'fidlist; short fident, fidmax; XVT_FONT_STYLE_MASK 'masks; viaw.h Mon Mar 20 14:40:45 1995 COLOR *colours; short *sizes; short *subsupsιzes; short stlcnt, stlmax, mt next_formιd; This is info that changes as we resize etc. LinkList *lιnk_under_cursor; LinkList 'links; short lent, lmax; AnchorList 'anchors; short acnt, araax; Link info in progress */ char *lιnk_to_url; char *lmk_to_orιgurl; Para *1mk_para; long xstart, ystart, yend; char *attr_lιst; Editing info */ char "pending; /* Hold a link while we wait to see if we got /* a double click. */ long multi_clιck_ιd, /* timer for selections */ struct lpnt { long h,v; ) press_pnt; XVT_FNTID cur_font. /* Font at cursor Selection sel; Position caret; Position press_pos; /' press_pnt in Position format */ long track_col; /' Up/Down tries to position caret here */ VPara *cheat; ' Used to speed up certain editing operations*/ unsigned int mouse_down. 1; unsigned int mouse_count: 3; unsigned int bookmarkmenu_dιrty: unsigned int wιndowmenu_dιrty: 1 unsigned int navιgatemenu_dιrty: 1, unsigned mt nocursor: 1; /" Not yet implemented */ unsigned int drag_and_drop: 1; unsigned int drag_marque. 1; unsigned int oldfreeze: 1, unsigned int fmdwrap: 1, unsigned int fmdwaslast: 1; unsigned int dontdrawsel: 1; unsigned int showform: 1; unsigned int showformchanged: unsigned int lmkshown: 1; unsigned int noticefocus: 1; /* Setting the title in the URL field gives it foe but we don't care */ unsigned int panefocus: 1; /* The pane currently has the focus */ unsigned int pane rapped: 1; /* The pane wants the pointer trapped */ VPara *float_ι_nages; short lent, lttiax; PNT dragsel[9] ; short dragent, dragas; struct lpnt lastdrag; short spn, soff, epn, eoff /* save selection */ /* Redraw info */ Redrawlnfo *ri; Positions of lines before the edit */ short rlen, rmax; short rslead, rsmd, rssubind, rslist. enum 3 ust_type rs 3 ust; short relead, reind, resubind, enum 3 ust_type re 3 ust; long re_y, re_x; long hdiff; /* difference between old and new size */ int rindex; /* a backspace may make the first word of the /* line move up to previous while an- viaw.h Mon Mar 20 14:40:45 1995 /* other char may make the last word */ /* move down to next */ short rsmds, rs as; /* Making a word a bigger font means we must */ short remds, remas; /* redraw the entire line */ WINDOW stat; /* Let's do our own status bar */ char stat_text[200] ; ) View; •endif html,b Wad Mar 22 09:18:10 1995 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved •ifndef XHTML_H •define XHTML_H ♦include <nshtml.h> /**** mapping to old Page structure *•**/ typedef struct page { struct page 'next, /* All pages linked together */ char *url, /* URL for this page, may be a local filename */ char *orιgurl, /* URL for this page, may be a local filename */ char "cachename; /* filename in page cache */ char *docnaπ_e; /* URL of document containing us */ struct document *doc; /* Document containing this page, need not be known */ char *contenttype, /* MIME content type */ char *title; char *faketιtle; /* Title given in the anchor that found this page •/ char *style, /* URL for style sheet */ struct style 'sheet,/* Pointer to a default style sheet */ char *upl, /* URL's for standard links */ char *uptιt; /* Titles for standard links */ char **otherlinks, /* contents of non-standard links */ char 'base; /* URL for BASE (whatever) */ char "headerinfo, /* Any stuff we d d not understand */ short 'headererrs, /* Any errors */ char 'headerargs, /* Any errors */ short 'trailerrs; /* Any after text' '/ char 'trailargs; /* Any after text' */ long expιratιon_t__me, /* Time specified on MIME expiration */ unsigned int isindex: 1, unsigned mt lsurl: 1; unsigned mt modifyable- 1; unsigned int changed: 1, unsigned int new: 1, unsigned t noname: 1; unsigned mt readin- 1, unsigned int haderrors: 1; unsigned int newwarned. 1, unsigned int frozen. 1, /* Temporary read only */ unsigned int eversaved 1, unsigned mt mcomextensions unsigned int orthodata . 1; /* not 3 ust a regular page */ unsigned mt oldchanged: 1,- unsigned int readstarted: 1; unsigned int dontsqueezenoops: 1, unsigned int saveas : 1, /* doing a Save As, rename when done */ unsigned int titlecompla ed : 1; unsigned int dismissed : 1; /* Page dismissed without saving (after being changed) */ unsigned mt dying : 1; /* Page being dismissed, but must reload to check links fi rst unsigned int linkschanged-1;/* At some point a link might have changed, need to reload on nosave */ unsigned t defersave:l, /* need to bring up chooser, */ unsigned t defersaveas:1; /* wait 'til not in runtasks */ unsigned mt savesucceded:1, unsigned mt saveasaltered:1; unsigned mt temporarychanged:1, /* Used to refresh icons */ Para *first; char *ιιpro_npt; /* prompt string for header isindex tag */ /* experimental V long refresh; /* live feed refresh interval */ long reload; /* time to reload */ /* experimental */ struct view 'views; /* List of all views looking at us (nextsame field)*/ ht l.h Wad Mar 22 09:18:10 1995 2 PRINT_RCD *prcd; /* Page setup info for Print command */ struct undo *undoes; struct undo 'redoes; char *cur_anchor; /* This should really be in the view rather than */ /* the page. There are race conditions where we */ /* could go to the anchor in the wrong window (but */ /* looking at same page) */ XVT_PALETTE palet; /* If not NULL, optimized for images on this page */ struct view *cur_view; /* View controlling the current 10 operation */ struct crud 'crud; } Page; /* convert between Page/HtmlPage: if dst is NULL, allocate a new destination and return it if deep is true, do a deep copy, otherwise shallow */ Page 'PageFromHtml PROTOTYPE((Page *dst, HtmlPage *src, int deep)); HtmlPage 'HtmlFromPage PROTOTYPE) (HtmlPage *dst, Page *src, int deep)); /* stubs for the old API */ Page *_PageRead PROTOTYPE( (Page *) ) ; int Page2File PROTOTYPE((Page *, char *, int)); int Page2URL PROTOTYPE( {Page *, char *) ) ; char *Page2Str PROTOTYPE({Page *, int)); int XVT_CALLC0NV1 WritePage(Page 'page, int dobase, int (*func) (/* ??? */), void *ctx) , ♦endif /tap/das Sat Mar 25 09:03:18 1995 /tmp/άma Sat Mar 25 09:03:57 1995 1566 Mar 7 14:47 DM_Cancel.c 350 Feb 26 17:28 DM_CloseDB.c 2057 Mar 14 21:59 DM_Create.c 1688 Feb 26 17:29 DM_DML.c 931 Feb 26 17:29 DM_Exec.c 667 Feb 26 17:29 DM_Flush.c 2223 Feb 26 17:28 DM_GetRow.c 2161 Feb 26 17:29 DM_OneRow.c 4327 Feb 26 17:29 DM_OpenDB.c 2209 Feb 26 17:29 DM_Select.c 5917 Feb 27 14:02 DM_TableInfo. 1580 Feb 26 17:29 DM_Trans.c 2518 Feb 26 17:29 DM_Update.c 1737 Feb 26 17:29 dm_StrTrim.c 867 Feb 26 17:29 dm_error.c Tua Fab 14 21:56:27 199S /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. ♦if XVT_OS_ISUNIX ♦ifdef sun •ifdef svr4 •define BSD_COMP •endif •endif •include <sys/types.h> ♦include <sys/1i eb.h> •include <sys/socket.h> •include <sys/ioctl.h> ♦include <sys/time.h> ♦include <netinet/ιn.h> •include <arpa/met.h> ♦include <netdb.h> ♦include <errno.h> ♦include <pwd.h> ♦include "skport.h" •define loctlsocket loctl ♦define closesocket close ♦define wsprintf sprintf void Pause(int left) { /* do nothing? */ } typedef char WSADATA; int WSAStartupO { return 0; ) void WSACleanupO {) •define WSAGetLastError() (errno) •define WSAEWOULDBLOCK EWOULDBLOCK •define WSAEINPROGRESS EINPROGRESS typedef struct sockaddr *LPsockaddr_m; typedef struct hostent *LPhostent; typedef u_long ιn_na_me; typedef ιn_name *LPm_name; •ifndef INADDR_NONE ♦define INADDR_NONE -1 ♦endif •define UserNaroe getpwuid(getuid() )->pw_name long inillisec!) { •ifdef svr4 return tιme(0) * 1000; ♦else struct ti eb tb; ft mef-ttb) ; return tb . time'1000 + tb .mill tm; •endif ) •el if XVT_OS_IS_WINOS •include <winsock . h> •include " skport . h" void Pause ( int left ) { Tue Fab 14 21:56:27 1995 if(left) YieldO ) typedef struct sockaddr FAR *LPsockaddr_ιn; typedef struct hostent FAR 'LPhostent; typedef u_long ιn_name; typedef m_name FAR *LPιn_name; typedef u_long FAR *caddr_t; •define UserName "wwwUser" long millisec() ( return GetTickCount() ; ) •elif XVT_OS == XVT_OS_MAC ♦include <SK_Port.h> •include <SK.h> •include <sys/errno.h> •define loctlsocket IOCTL •define closesocket CLOSE •define wsprintf sprintf void Pause( t left) { /* do nothing? */ ) typedef char WSADATA; int WSAStartup() { return 0; ) void WSACleanup() {} •define WSAGetLastError() (errno) •define WSAEWOULDBLOCK EWOULDBLOCK •define WSAEINPROGRESS EINPROGRESS typedef struct sockaddr *LPsockaddr_m; typedef struct hostent *LPhostent; typedef u_long ιn_name; typedef m_name *LPm_name; •ifndef INADDR_NONE •define INADDR_NONE -1 •endif long millisec() { return ( (long) (clock() *1000 / CLOCKS_PER_SEC) ) ) ♦endif •define NULL_SOCKET -1 lib Sat Mar 25 09:29:36 1995 Client Communications Layer Library that handles all communications tasks from the client to the server (or other servers). Creates, manages and disposes of connection requests and returns responses. -r—r 1974 Jan 31 12:33 auth.c -r—r 3258 Jan 31 12:33 crud.c -r—r 2302 Mar 20 12:13 crudio.cxx -r—r 573 Mar 3 12:15 crudshi .c -r—r 2792 Feb 3 18:23 docrud.cxx -r—r 5076 Mar 6 12:42 form.c -r—r 5253 Jan 31 12:35 gif.cxx -r—r 1148 Jan 31 12:37 gif.h -r—r 2283 Mar 10 12:42 gifshim.cxx -r—r 3936 Mar 23 13:13 guess.c -rw-r 4150 Mar 23 13:13 guess.c- -r—r 1318 Jan 31 12:36 htstring.h -r—r 8280 Mar 3 12:16 htutils.h -r—r 7454 Jan 31 12:33 htuu.c -r—r 923 Jan 31 12:36 htuu.h -r--r 996 Mar 3 12:14 lfunc.c -r—r 85450 Mar 23 17:27 lhtml.c -rw-r 85399 Mar 23 17:27 lhtml.c- -r—r 9598 Mar 23 13:10 local.cxx -rw-r 9327 Mar 23 13:10 local.cxx- -r--r 260 Mar 10 13:57 lxvt.h -r—r—r— 1863 Mar 10 14:06 makefile -r--r 244 Jan 31 12:35 mem.cxx -rw-rw-r— 1005 Mar 16 18:33 outs - χ- -χ 939 Jan 31 12:35 response.cxx -r— —r— 9973 Jan 31 12:38 sk.h -r—r—r— 4097 Jan 31 12:38 skport.h -rw-rw-rw- 38920 Mar 23 13:14 str.o -r—r 2793 Feb 10 18:02 task.cxx drwxrwxr-x 512 Feb 24 12:11 tilde -r—r 32595 Mar 20 12:13 web.cxx -r--r 4760 Mar 22 14:53 xcomm.c -r--r 2099 Feb 14 21:56 xcomm.h -r—r 965 Mar 2 19:00 xdoc.c -r--r 25653 Mar 23 13:10 xlocal.c -rw-r 25653 Mar 23 13:10 xlocal.c- Files included for reference: crud.c : builds crud—create, retrieve, update, delete—structures. cruds are the main structure to hold requests. crudio.cxx: handles the client input/output stream. crudshim.c: runs a task. docrud.cxx: executes a crud request. lhtml.c: handles formatting and parsing HTML. local.cxx: handles local operations (as opposed to remote over the net) response.cxx: routines to handle returns from the server. str.cxx: routines to handles strands, main I/O stream. web.cxx: builds http requests, builds TCP requests. lib Sat Mar 25 09:29:36 1995 2 xco m.c: TCP socket code. xdoc.c: routine to assist with directories for collections. xlocal.c: routines to mainpulate file/URL paths cross-platform. crud.c Tαa Jan 31 12:33:48 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ ♦include <stdιo.h> •include <strιng.h> ♦include "crud.h" •include "l unc.h" static Crud waiting = {&waιtιng, Swaitmg, X) ; static Crud running = ; static Crud prefetch = X); static Crud Oldpre = {.prefetch; Crud 'newCrud)crudtype type, Auth 'auth, char *url, Form 'form, int sid, int (*func) (voιd *,ιnt), void *ctx) { Crud *crud = (Crud *Imyalloc(εizeof(Crud) ) , if(crud) ( crud->type = type; crud->auth = auth; crud->url = copy(url); crud->form = form; crud->sιd = sid; crud->func = func; crud->part = 0; crud->ctx = ctx; crud->comm = 0; crud->method = NULL; strcpy(crud->status, ""); crud->abort = 0; crud->ιnfo = crud->reload = 0; crud->sιnce = 0; crud->prev = &waitιng; crud->next = waiting.next; waiting.next->prev = crud; waiting.next = crud; } return crud; } int _ιnfo(char *,...); /* this should be static, but we want to use in crudio */ void FreeCrud(Crud *crud) { char 'crudtype = "CRUDXB"; _ιnfo("free-.c %s %s\n" , crudtype[crud->type] , crud->url, crud->status) ; crud->prev->next = crud->next; crud->next->prev = crud->prev; myfree(crud->url) ; myfree(crud->method) ; myfree(crud->queryStrιng) ; myfree(crud->protocol) ; myfree(crud) ; if(oldpre == crud) oldpre = ^prefetch; •if 0 for(crud = running.next; crud '= irunning; crud = crud->next) __mfo("rq-%c %s %s\n", crudtype[crud->type] , crud->url, crud->status) crud.c Tuβ Jan 31 12:33:48 1995 2 for(crud = prefetch.next; crud != {.prefetch; crud = crud->next) _info("pq-%s %s\n", crud->url, crud->status) ; •endif } static void PlaceCrudtCrud 'crud, Crud 'list) { crud->prev->next = crud->next; crud->next->prev = crud->prev; crud->prev = list->prev; crud->next = list; lιst->prev->next = crud; list->prev = crud; Crud 'CreateCrudfchar *url, Desc 'desc, int sid) { Auth *auth = (desc &_. desc->auth ? desc->auth : GetAuth(url)) ; Form *form = (desc ? desc->form : (Form *)0); return newCrud(C, auth, url, form, sid, 0,0); ) Crud *UpdateCrud(char *url, Desc 'desc, int sid) { Auth 'auth = (desc && desc->auth ? desc->auth : GetAuth(url) ) ,- Form *form = (desc ? desc->form : (Form *)0); return newCrud(U, auth, url, form, sid, 0,0); } Crud *DeleteCrud(char *url) { return newCrud(D, GetAuth(url) , url, 0, 0,0,0); ) Crud *RetrieveCrud(char *url, Form *form) { return newCrudtR, GetAuth(url ? url : form->URL) . url, form, 0,0,0); ) Crud *BrowseCrud(char *url) { return newCrud(B, GetAuth(url) , url, 0, 0,0,0); ) Crud *PrefetchCrud(char *url) ( if(url == (char *)0) { oldpre = prefetch.next; return (Crud *)0; } else { Crud 'crud = newCru (R, GetAuth(url) , url, 0, 0,0,0); PlaceCrud(crud, oldpre); return crud; } ) Crud 'QueueCrud(Crud 'crud, int Cfunc) (void *,int), void *ctx) { crud->func = func; crud->ctx = ctx; PlaceCrud lcrud, {.running) ; return crud; ) int AbortCrud (Crud *crud) crud.c Tua Jan 31 12:33:48 1995 3 { if(crud) { sprintf (crud->status, "aborted %s", crud->url), return crud->abort = 1; ) return 0; } Crud *RunQHead() { return running.next; ) Crud *PreQHead() { return prefetch.next; ) crudio.cxx Mon Mar 20 12:13:43 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •include "crud.h" •include "str.h" •include "lfunc.h" •include "task.h" /* this is in it's own file so that we don't necessarily pull in all of comm when using Cruds */ extern "C" { extern int DoCrudlCrud *); extern int CheckCrud(Crud *) ,- extern void FreeCrud(Crud *); extern Crud 'RunQHeadO; extern Crud 'PreQHeadO; }; static int last = 0; static int count = 0; static int max = 16; /* limit simultaneous connections */ static int cache = 1; class crudtask : public task ( int rid; Crud *crud; cruddone() ; public: crudtask(Crud *) ; partial() ; ); int crudtask: :cruddone() { --count; if(rid) { if(cache &{_ crud->type == R) strand: :cache(rid, crud->url, crud->auth) ; if(crud->func) (crud->func) (crud->ctx, rid) ; } delete (task *)crud->coιπm; FreeCrud(crud) ; return finish(rid) ; } crudtask: :crudtask(Crud *_crud) : task(0) { count++; crud = _crud; if(rid = DoCrud(crud) ) cruddone() ; ) int crudtask: :partial() { if( !crud->comm || crud->abort) { return cruddone{) ; ) task *tk = (task *)crud->co_πm; if(tk->done) { crudio.cxx Mon Mar 20 12:13:43 1995 2 rid = tk->state; return cruddone{) ; } else ιf(tk->prog) { if (crud->part) (crud->part) (crud->ctx, tk->state) ; ) return block(tk->state) ; } extern "C" { mt SeeCrudsRun() { Crud *c, *n; for(c = RunQHeadO; count < max && c->type '= X; c=n) { n = c->next; new crudtask(c); } forlc = PreQHeadf); count < max && c->type '= X, c=n) { n = c->next; if( 'c->comm) new crudtask(c) , } if(last '= count) { _ιnfo("crudtasks- %d\n" , count); last = count; ) /* get rid of any "instantaneous" strands */ CacheReap() ; return 0; ) void CrudRundown(voιd) { do { RunTasks() ; ) whιle(RunQHead()->type '= X) ; mt CrudlnQueue(Crud *crud) { Crud *c; for ( c=RunQHead() ,- c->type '= X fc& c'=crud; c=c->next ) ; return( c==crud ) ; ) int SyncCrudlCrud 'crud, mt Cfunc) (void *), void *ctx) { while ( CrudlnQueue(crud) ) RunTasks() ; return 1; } int SetMaxOutstandingCruds (mt n) { max = n; return old; } int SetCrudCaching(int b) { int old = cache; cache = b, crudio.cxx Mon Mar 20 12:13:43 1995 return old; } ) docrud.cxx Fri Fab 3 18:23:21 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved. */ •include <strιng.h> •include "crud.h" •include "str.h" •include "response.h" •include "guess.h" static int lSlocaKchar *url) { return! 'strstr(url, "://")),- } int webcrudlCrud *); int localcrud(Crud *); int popcrud(Crud *); int internal(Crud *crud) , int mailtofCrud *crud) ; extern "C" { mt ('HtmlHotlist) (void) = (int (*)())0; mt DoCrud(Crud *crud) { char *dest = (crud->url ' crud->url • crud->form->URL) , if(pmatchf"npi: " ,dest) ) { if(strcmp("npι://hotlιst",dest)==0 && HtmlHotlist) return HtmlHotlist() ; if(crud->type == R) return internal(crud) ; return f vehundred("illegal internal operation"), } else if(pmatch("maιlto: ",dest) ) { return mailto(crud) ; ) else if(p atch)"pop: " ,dest) ) { return popcrud(crud) ; } else if dslocal(dest) ) { return localcrud(crud) ,- ) return webcrud(crud) ; } } int internal(Crud *crud) { static int count = 0; wstrand ws; ws.create(200, "text/html") ; ws.pr t("<FORM ACTION=\"npι:/foobar/%d\">" , count++); char *old = GetFormValue(crud->form, "foobar"); if(old) ws.print("you had typed: %s<BR>", old) ; ws.print("<INPUT NAME=\"foobar\">") ; ws.print("<INPUT TYPE=\"submit\" VALUE=\"tryme\">") ; ws.prιnt("</FORM>") ; return ws.close() ; } extern int smtp(char *, char *, char *, char *, Crud *); mt maιlto(Crud *crud) { switch(crud->type) { docrud.cxx Fri Fab 3 18:23:21 1995 case R: if(crud->info) break; if(crud->url) { char 'addr = pmatch!"mailto: ",crud->url) ; wstrand ws; ws.create(200, "text/html"); ws.print("<Hl>mailto: service</Hl>") ; ws.print("<FORM ACTION=\"mailto:%s\"> , addr) ; ws.print("Press <INPUT TYPE=\"submit\ VALUE=N"sendN" when " ) ; ws.prin ("you have finished composing your message.<HR>") ,- ws.print("<B>To:</B> <CODE>%s</CODExBR>", addr); ws.print("<B>Subject:</B> <INPUT NAME=\"sub ect\ SIZE=40><HR>") , ws.print("<INPUT NAME=\"body\" SIZE=60,20>") ; ws.print("</FORM>") ; return ws.close)); ) else if(crud->form) { char 'user = pmatch)"mailto: ",crud->form->URL) ; char 'host = strchr(user, ' & ' ) ; if( i ser) return f vehundred("usage: mailto:user@host" ) ; if( !host) host = "localhost",- else return smtp(user, host, GetFσrmValue(crud->form, "subject"), GetFormValue(crud->form, "body"), crud); ) case C: case U: { char 'user = pmatch)"mailto: ",crud->url) ; char 'host = strchr(user, '@' ) ; if( luser) return fιvehundred("usage: mailto:userθhost" ) ,- if( !host) host = "localhost"; else *host++ = 'Non¬ return smtp(user, host, NULL, NULL, crud) ; ) case D: case X: break; } return fivehundred( "error in mailto") crudabia.c Fri Mar 3 12:15:38 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ ♦include <stdio.h> ♦include "crud.h" ♦include "str.h" ♦include "task.h" extern Crud 'RunQHead() ; extern int SeeCrudsRun() ; extern int _crud_error(char *fmt, ...); void RunCruds(int verbose) { static int tasked = 0; if)! asked) { tasked = 1; ♦if 0 AddTask(0, 0, SeeCrudsRun, 0) ,- ♦endif AddTaskSeeCrudsRun(0, 0) ,- ) while(RunQHead()->type != X) { if(verbose) _crud_error(" r%80s" , RunQHead))->status) ; RunTasks() ; ) if(verbose) _crud_error("Nn" ) ; CacheFlush(O) ; lhtml.c Tbu Mar 23 17:27:18 1995 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved ♦include <stdιo.h> •include <strιng.h> •include <ctype.h> •include <assert.h> •include <stdlιb.h> •if defined! sun ) I I defined) hpux ) | | defined! svr4 ) | | defined! osf ) # include <stdarg.h> # include "lxvt h" /* XVT says I really need the defn of XVT_CALLC0NV1 */ •else • include <xvt.h> ♦endif •include 'nshtml.h' ♦include ' lfunc h" •include 'xlocal.h" •include 'memmask h" •define DEF_ISINDEX_PROMPT "This is a searchable index Enter search keywords static t charsearch PROTOTYPE((char *)), static int htmlsearch PROTOTYPE((char *)), static int outch PROTOTYPE((mt)) , static int outst PROTOTYPE! (char *)), static int outlat lhex PROTOTYPE((in )) , static t outchar PROTOTYPE((int)) , static int outstr PROTOTYPE) (char *)), static int outnstr PROTOTYPE((char *,mt)), static int OutLmk PROTOTYPE((char *,char *,char *)) static t OutHeader PROTOTYPE( (HtmlPage *,mt)), static int OutPara PROTOTYPE( (HtmlPage *, Para *)) static t OutHtmlPage PROTOTYPE! (HtmlPage *,ιnt)) static int inch PROTOTYPE) (void) ) , static int ungetch PROTOTYPE((int)) , static mt ungetchr PROTOTYPE<(int)) , static void ungeterr PROTOTYPE( (HtmlPage *,int,int,int) ) , static void addheadererr PROTOTYPE! (HtmlPage *,ιnt,mt)) static void addtrailerr PROTOTYPE) (HtmlPage *,int,int)) static void ungetend PROTOTYPE((int)) , static void ungettag PROTOTYPE( (int, t) ) , static int slurptag PROTOTYPE! (void) ) , static char 'slurpTagText PROTOTYPE! (int) ) static void newnest PROTOTYPE((in )) , static int inchr PROTOTYPE( (void) ) , static t indec PROTOTYPE) (void) ) , static void skip PROTOTYPE( ( t) ) , static t hasListParent PROTOTYPE((Para *)), static struct attribs 'parseAttrs PROTOTYPE( (HtmlPage *,mt,char *,ιnt,mt) ) , static struct attribs 'slurpParseAttrs PROTOTYPE) (HtmlPage *,ιnt, mt)). static mt unnest PROTOTYPE( (HtmlPage *,ιnt,mt)), static char *slurp2end PROTOTYPE( (HtmlPage *,ιnt)), static void slurpHeadltem PROTOTYPE! (HtmlPage *,mt,mt)), static void slurpHeader PROTOTYPE) (HtmlPage *)), static int end2base PROTOTYPE) (long,long,long) ) , static void makeSearchForm PROTOTYPE{ (HtmlPage *,Para *)), static Para 'slurpParaList PROTOTYPE) (HtmlPage * Para *)), static Para *slurpLιst PROTOTYPE{ (HtmlPage *,Para *)), static void slurpBody PROTOTYPE)(HtmlPage *)), static HtmlPage *slurpHtmlPage PROTOTYPE) (HtmlPage *)), static t parse_null PROTOTYPE) (void *)), /* There is a macro of this in viewdraw c for speed */ int navι_ιsspace(ιnt ch) { if ( ch==' ' II ch=='Nn' || ch=='Nr' || ch=='Nt' ) lhtml.c Tfau Mar 23 17:27:18 1995 return 1; return( 0 ); } /* Mappings between non-ASCII characters (parity bit set) and standard mneumonics */ /* We always need the latinl table so that we can map &#xx; to latinl and then*/ /* to the local character set */ static struct chartab latinlcharnames[] = { /* capital AE diphthong (ligature) */ /* capital A, acute accent */ /* capital A, circumflex accent */ /* capital A, grave accent */ /* capital A, ring */ /* capital A, tilde */ /* capital A, dieresis or umlaut mark /* capital C, cedilla */ /* capital Eth, Icelandic */ /* capital E, acute accent */ /* capital E, circumflex accent */ /* capital E, grave accent */ /* capital E, dieresis or umlaut mark /* capital I, acute accent */ /* capital I, circumflex accent */ /* capital I, grave accent */ /* capital I, dieresis or umlaut mark /* capital N, tilde */ /* capital O, acute accent */ /* capital O, circumflex accent */ /* capital O, grave accent */ /* capital O, slash */ /* capital 0, tilde */ /* capital O, dieresis or umlaut mark /* capital THORN, Icelandic */ /* acute accent */ /* circumflex accent */ /* grave accent */ /* dieresis or umlaut mark /* acute accent */ /* cute accent */ /* ircumflex accent */ /* small ae diphthong (ligature) */ /* small a, grave accent */ /* ampersand */ /* small a, ring */ /* small tilde */ /* small dieresis or umlaut mark / /* small cedilla */ /* small acute accent */ /* small circumflex accent */ /* small grave accent */ /* small eth, Icelandic */ /* small e, dieresis or umlaut mark /* greater than */ /* small i acute accent */ /* small l circumflex accent ~ l /* small l grave accent */ /* small l dieresis or umlaut mark /* less than ■ I /* small n, tilde */ /* small o, acute accent */ /* small o, circumflex accent /* small o, grave accent */ /* small o, slash */ /* small o, tilde */ lhtml.c Tbu Mar 23 17:27:18 1995 "iouml", Oxf6 }, I " small o, dieresis or umlaut mark */ "S-quot", '"' }, /" totally useless, but documented */ "iszlig", Oxdf ), /' small sharp s, German (sz ligature) */ "Sthorn", Oxfe ), /" small thorn, Icelandic */ "fcuacute", Oxfa ), /' small u, acute accent */ "iucirc", Oxfb ), /' small u, circumflex accent */ "iugrave", Oxf9 }, /* small u, grave accent */ "fcuuml", Oxfc }, I * small u, dieresis or umlaut mark */ "iyacute", Oxfd }, /" small y, acute accent */ "&yuml", Oxff }, / ' small y, dieresis or umlaut mark */ MCOM extensions, semi-standard */ "-.copy", 169 }, "fcreg", 174 }, /* GWW: The following are non-standard: '/ 'θnobreakspace" , OxaO) , /* non-breaking space */ •define _C_NBS OxaO "βexclamdown", 161 /* down exclamation point "Scent", 162 /* cent sign */ "©sterling",163 /* pound sign */ "©currency" ,164 "βyen", 165 /* yen sign */ "@brokenbar",166 "βsection", 167 "©diaeresis",168 "©dieresis",168 "βordfeminine" ,170 "θguillemotleft" ,171 /* guillemot gauche "©notsign", 172 "©hyphen", 173 "©macron", 175 "θdegree" , 176 "©plusm us",177 "θtwosupenor" ,178 "θthreesupeπor" , 179 "©acute", 180 "θparagraph" ,182 "θperiodcentered" ,18 /* centered period */ "βcedilla", 184 "βonesuperior" ,185 "@ordmasculine" ,186 "θmasculine",186 ) "θguillemotright",187 guillemot doigt */ "θonequarter",188 "θonehalf", 189 "Sthreequarters" ,190 "θquestdown",191 /* question mark down NULL }; /* Should this depend on Windowing system or on OS, what does X running on */ /* Mac or Windows do with these characters' */ •if XVTWS==MTFWS I I XVTWS==XOLWS /* X uses Latin 1 encodings */ static struct chartab *charnames = latinlcharnames,- static struct unknownchartab unknownchars[] { {0, NULL } ); static struct chartab charnames[] = { { "iAElig", 174 }, /* capital AE diphthong (ligature) */ { "4-Aacute", 231 ), /* capital A, acute accent */ { "fcAcirc", 229 }, /* capital A, circumflex accent */ lhtml.c Tbu Mar 23 17:27:18 1995 /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* capital /* capital U, acute accent */ /* capital U, circumflex accent */ /* capital U, grave accent */ /* capital U, dieresis or umlaut mark */ /* capital Y, acute accent */ /* small a, acute accent */ /* small a, circumflex accent */ /* small ae diphthong (ligature) */ /* small a, grave accent */ /* ampersand */ /* small a, ring /* small a, tilde */ /* small a, dieresis or umlaut mark /* small c, cedilla */ /* small e, acute accent */ /* small e, circumflex accent */ /* small e, grave accent */ /* small eth, Icelandic */ /* small e, dieresis or umlaut mark /* greater than */ /* small l acute accent */ /* small l circumflex accent */ /* small l grave accent */ /* small i dieresis or umlaut mark /* less than */ /* small n, tilde */ /* small o, acute accent */ /* small o, circumflex accent */ /* small o, grave accent */ /* small o, slash */ /* small o, tilde */ /* small o, dieresis or umlaut mark */ /* totally useless, but documented */ /* small sharp s, German (sz ligature) /* small thorn, Icelandic */ /* small u, acute accent */ /* small u, circumflex accent */ /* small u, grave accent */ /* small u, dieresis or umlaut mark */ /* small y, acute accent */ /* small y, dieresis or umlaut mark */ MCOM extensions. semi-standard 7 lhtml.c Thu Mar 23 17:27:18 1995 breaking space */ exclamation point sign */ d sign */ sign */ times spelled one way, sometimes another */ "θordfeminine",187 "θguillemotleft" ,199} "θnotsign", 194 ) "©logicalnot" ,194 "©hyphen" , "©macron", 248 "©degree", 161 "θplusminus" ,177 "θtwosuperior" ,26 "θthreesupeπor" ,25 "©acute", 171 "βmu", 181 "©paragraph",166 "©perlodcentered" 225 /* centered period */ "©cedilla", 252 "©onesuperior" ,23 "©ordmasculine", 188 "©masculine" ,188 "©guillemotπght" ,200 /* guillemot doigt */ "©onequarter" ,22 "©onehalf, 21 "θthreequarters" ,24 "©questdown",192 /* question mark down NULL }; static struct unknownchartab unknownchars[] = { {165, "."), /* Bullet */ {170, "TM" ) , {201, ". ."). {207, "oe"), {206, "OE"), {208, "-"), {209, "--"), {210, '), {211, '} , {212, " '"}, {213, " "}. {222, "fi"}, {223, "fl"}. {0, NULL) }; This appears to be a super-set of latm-l = { capital AE diphthong (ligature) */ capital A, acute accent */ capital A, circumflex accent */ lhtml. c Thu Mar 23 17:27:18 1995 lhtml.c Thu Mar 23 17:27:18 1995 { "tcopy", 169 }, { "ireg" , 174 } , /* GWW: The following are non-standard: { "θnobreakspace" , OxaO), /* non-breaking space */ •ifdef _C_NBS ♦ undef _C_NBS •endif •define _C_NBS OxaO "©exclamdown" , 161 /* down exclamation point */ "©cent", 162 /* cent sign */ "©sterling" ,163 /* pound sign */ "©currency" ,164 "©yen", 165 /* yen sign */ "©brokenbar",166 "©section", 167 "©diaeresis",168 "©dieresis" ,168 '©ordfeminine" ,170 "θguillemotleft" ,171) guillemot gauche */ "θnotsign", 172 ) "©hyphen", 173 ) "θmacror. 175 ) "θdegre- , 176 "βplusπinus" ,177 "©twosuper- - ,178 "@thre* r.._erior" 179 "©acute", 180 "© u", 181 "©paragraph",182 "©periodcentered ,183 /* centered period */ "©cedilla", 184 "θonesuperior" ,185 "θordmasculine" ,186 "©masculine",186 "θguillemotright",18 /* guillemot doigt */ "θonequarter" ,188 "©onehalf", 189 "©threequarters" , 190 "©questdown",191 /* question mark down */ NULL nownchartab unknownchars!] = /* Bullet */ {0, NULL) }; •endif /* Now for HTML keywords, or whatever */ static struct attribs none[] = {{ 0 }}; static struct attribs a_list[] = { {"HREF", VAL_STR}. {"NAME", VAL_STR}, {"TITLE" , VAL_ST } , lhtml.c Thu Mar 23 17:27:18 1995 8 {"TYPE"), /* What's this' */ static struct attribs base_lιst[] = { {"HREF", VAL_STR}, {0) }; static struct attribs br_lιst[] = { {"CLEAR", VAL_STR) , {0} ); static struct attribs font_lιst[] = { {"SIZE", VAL_NUM), {0) }; static struct attribs lιnk_lιst[] = { {"HREF", VAL_STR. , /* Must be first, see slurpHeadltem */ {"TITLE", VAL_STR) , /* Must be second, see slurpHeadltem */ {"REL", VAL_STR) , {"TYPE", VAL_STR) , /* Should it be TYPE or REL', well accept either */ {"REV", VAL_STR) , {0) }; static struct attribs ιmg_lιst[] = { {"SRC", VAL_STR) , {"ALIGN" , VAL_STR) , {"ALT", VAL_STR) , {"ISMAP"} , {"WIDTH" ,VAL_NUM} , {"HEIGHT* ,VAL_NUM} , {"BORDER",VAL_NUM) , {"VSPACE" ,VAL_NUM} , {"HSPACE",VAL_NUM) , {0} }; static struct attribs p_lιst[] = { {"ALIGN" , VAL_STR} , {0} }; static struct attribs form_lιstU = ( {"ACTION" , VAL_STR) , {"METHOD", VAL_STR} , /* Or should the options be GET and POST' */ {0} }; static struct attribs optιon_lιst[] = { {"VALUE" , VAL_STR) , {"SELECTED"}, {0} }; static struct attribs textarea_lιst[] = { {"ROWS", VAL_NUM}, {"COLS", VAL_NUM}, {"NAME", VAL_STR) , {0} }; static struct attribs εelect__lιst[] = { {"NAME", VAL_STR}, {"SIZE", VAL_STR}, {"MULTIPLE" , VAL_STR} , {0} ); static struct attribs ιnput__lιst[] = { {"TYPE", VAL_STR} , lhtml.c Tbu Mar 23 17:27:18 1995 {"NAME", VAL_STR) , {"SIZE", VAL_STR}, {"VALUE", VAL_STR} , {"SRC", VAL_STR) , /* Used for the un-documented image input type*/ {"ALIGN", VAL_STR}, /* ditto */ {"CHECKED"} , ("MAXLENGTH" , VAL_NUM} , {0} tatic struct attribs lιst_lιst[] = { {"TYPE", VAL_STR) , {"START", VAL_NUM}, {0} tatic struct attribs lι_lιst[] = { {"TYPE", VAL..STR}, {"VALUE", VAL_NUM) , {0} tatic struct attribs ιsmdex_lιst [] = { {"PROMPT" , VAL_STR} , {0} tatic struct attribs hr_lιst [] = ( {"SIZE", VAL_NUM}, {"WIDTH", VAL_STR) , {"ALIG " , VAL_STR} , {"NOSHADE"} , {0} * experimental */ tatic struct attribs refresh_lιst[] = { {"SECONDS" , VAL_NU } , {0} experimental -- '/ struct keyparse { char 'name; struct attribs *attr; unsigned char html_tag; unsigned int terminated:!, ): "A" "ADDRESS" , "B" "BASEFONT", "BASE" "BODY" "BLOCKQUOTE' "BR" "CENTER" ■ CITE" ■ CODE" "COMMENT", "DD" "DFN" "DIR" "DL" "DLC" "DT" "EM" "FONT" lhtml.c Thu Mar 23 17:27:18 1995 10 ); static int charsearch(name) char "name; { for ( ι=0; charnames[i].name'=NULL ; ++ι ) ptl = charnames[i].name*1; pt2 = name; while ( *ptl==*pt2 ) { if ( *ptl=='N0' > return i; ++ptl; ++pt2; } ) return -1; static mt htmlsearch(name) char 'name, ( lhtml . c Thu Mar 23 17 : 27 : 18 1995 11 int l , char *ptl , *pt2 ; mt chl , ch2 , for ( ι=0, keynames[lJ.name'=NULL , ++ι ) { ptl = keynames[l].name, pt2 = name, for (, ; ) { chl = *ptl++, ch2 = *pt2++, if ( chl=='N0' I I ch2=='N0' ) break; if ( lslower(chl) ) chl = toupper(chl) , if ( islower(ch2) ) ch2 = toupper(ch2) if ( chl'=ch2 ) break, } if ( chl=='N0' tt ch2=='N0' ) return l, } return -1, } static char *char2names(256) /* To go from INTERNAL to HTML */ static struct keyparse *key2names[256] , /* To go from INTERNAL to HTML */ static t mited, /* Variables used for output */ static int ch_pos=0, static mt docrlfs=l, /* Variables used for input */ static unsigned char 'ungot, static mt rpos, rmax, rlen, static char 'tagbuf, static mt tmax; static char *pbuf, static long p ax, static t 'nesting, 'nestoff static int nlevel, nmax, static int foundplain, static int pnum, static HtmlPage 'page, /* Initialize whatever needs to be Currently this consists of generating */ /* a reverse mapping from characters to char names (like tquot) , and another */ /* from HTML TAGs to their names */ void lnitcharnames() { f ( ' ited ) { ited = 1; for ( ι=0 ; unknowncharstl] str'=NULL; ++ι ) char2nair.es[unknownchars[1] .ch] = unknownchars[i] str, for ( ι=0, charnames[i] name'=NULL , ++ι ) char2names[charnames[I] .ch] = charnames[I] name, char2names[ '"' ] = NULL, /* There is a defn for this, but */ /* no reason to use it, that I see */ for { ι=0, keynames[l].name'=NULL , ++ι ) key2names[keynames[i] html_tag] = tkeynames[l] , } nesting = (mt *) myalloc(100*sιzeof( t) ■ , nestoff = (mt *) myalloc(100*sιzeof(int) ) , nmax = 100, lhtml.c Tbu Mar 23 17:27:18 1995 12 /* Clean up whatever needs to be, currently that means freeing stuff we've */ /* allocated. The files should have been closed already */ void cleanupparse () { if ( ungot'=NULL ) myfree((char *)ungot), ungot = NULL; if ( nesting'=NULL ) myfree((char *)nestιng); nesting = NULL; myfree(nestoff) ; nestoff = NULL; if ( tagbuf>=NULL ) myfree(tagbu ) ; tagbuf = NULL; if ( pbuf'=NULL ) myfree(pbuf) ; pbuf = NULL, } static mt (*outfunc) (void *,ιnt); static void *outctx; typedef struct { mt bpos, int blen, char *body; } strctx,- static int WriteStr(ctx, ch) strctx *ctx; char ch; { if(ctx->bpos >= ctx->blen) { ctx->blen += 20000; if( (ctx->body = myrealloc(ctx->body,ctx->blen) ) == NULL) return EOF; ) return ctx->body[ctx->bpos++] = ch; } static int WrιteFιle(ctx, ch) FILE *ctx, char ch; { return putc(ch, ctx), } /* Lowest level output routine. Writes one character either to a file or an */ /* internal string (which may need to grow) Also changes spaces to newl es*/ /* if the line is too long */ static mt outch(ch) int ch; { if ( ++ch_pos>72 tt ch==' ' tt docrlts ) ch = 'Nn' , if ( ch=='Nn' ) ch_pos = 0; if(outfunctoutctx, ch) == EOF) return 0; return 1,- } /* Output a string with no interpretation */ static int outst(str) char *str; { while ( *str ) { if ( !outch(*str) ) return 0; ++str; ) return 1, ) /* Output a string with no interpretation */ static mt outstntstr,n) char *str; mt n; { while ( *str t& —n>=0 ) { lhtml.c Thu Mar 23 17:27:18 1995 13 f ( 'outch(*str) ) return 0; ++str; ) return 1; } /* Take this character, convert it into latinl */ char * LatinlCharNamednt ch) { int i; static char buffer[10], if ( ch<0 ) ch+=256; lf ( ch==_C_NBS ) return( "<SP>" ) ; else if ( char2nair.es[ch)==NULL || ch=='- ' ) ( buffer[0)=ch; buffer[1]='NO' ; return! buffer ); } else if ( *char2names[ch] '='©' ) { strcpyfbuffer,char2names[ch] ) ; strcat(buffer, ";") , return! buffer ) ; } else { if ( charnames'=latιnlcharnames ) { for ( ι=0; latinlcharnames[l] .name'=NULL tt strcmptlatinlcharnames[l] .name,char2names[ch] ) '=0 , ++ι ); if ( latinlcharnames[l] .name==NULL ) /* Shouldn't happen */ buffer[0]=ch; buffer[1]='NO' ; return! buffer ), ch = latinlcharnames[l] .ch; ) sprintf(buffer, "t#%d, " ,ch) , return(buffer) ,- } } /* Take this character, convert it into latinl, and then output that in hex */ static int outlatιnlhex(ch) int ch; { int l ; if ( charnames'=latιnlcharnames ) { for ( ι=0; latinlcharnames[l] .name'=NULL tt strcmp(latinlcharnames[l] .name,char2names[ch] )'=0 ,- ++1 ); if ( latinlcharnames[i] .name==NULL ) /* Shouldn't happen */ return( outch(ch) ) ; ch = latinlcharnames[I] .ch; } if ( loutch('t')) return false; lf ( Outch('#')) return false; if ( 'outcht '0'+(ch/100) ) ) return false, if ( 'outchl O'+( (ch%100)/10) ) ) return false; if ( OutchCO'-. (ch%10) ) ) return false, return(outch) ';')); } /* Output a character looking out for the non-breakmg space (which becomes */ /* <SP>) and any of the magic characters HTML understands */ static t outchar(ch) int ch; { if ( ch<0 ) ch+=256; if ( ch==_C_NBS ) return( outst("<SP>") ) ; else if (( char2names[ch]==NULL || ch=='-' ) tt ' (cht0200) ) return) outc (ch)), else if ( char2names[ch]==NULL || *char2names[ch]=='©' ) /* Non-standard name. Use lhtml.c Thu Mar 23 17:27:18 1995 14 hex */ return) outlatιnlhex(ch) ) ; else { if ( 'outst (char2names[ch] ) ) return(O); return( outch(';')), ) } char *local21atml (char *s) { unsigned char *str = (unsigned char *) s, int i,- /* return(s) ,- */ while ( *str'='N0' ) { if ( Cstrt0200) tt char2names[*str] '=NULL ) { for ( ι=0; latinlcharnames[1] .name 1 =NULL tt strcmp(latinlcharnames[l] .name,char2names[*str] ) '=0 , ++ι ) if ( latinlcharnames[l] .name 1 =NULL ) •str = latinlcharnames[I) .ch, ) ++str; } return(s) ,- } char *latml21ocal(char *s) { unsigned char "str = (unsigned char *) s, mt 1,3; /* if ( charnames==latιnlcharnames ) return(s) ,- */ while ( *str'='N0' ) { if 1 *strt0200 ) { for ( i=0; latinlcharnames[I] .name 1 =NULL tt latinlcharnames[i] .ch 1 =*str; ++ι ) if ( latinlcharnames[i] .name 1 =NULL ) { for ( 3 =0; charnames[3] .name'=NULL tt strcmp(charnames[3] .name, latinlcharnames[1] .name) '=0 , ++3 ), 1f ( charnames [3] .name'=NULL ) *str = charnames[3] .ch; ) ) ++str, } return(s) ,- } /* Output a string of characters where each needs to go through translation */ /* as described above */ static int outstr(str) char *str; { while { *str ) { if ( loutchar(*str) ) return 0; ++str; } return 1; } /* Output a string of characters where each needs to go through translation */ /* as described above. The end of the string is determined by the length */ /' rather than the presence of a NUL */ lhtml.c Tbu Mar 23 17:27:18 1995 15 static int outnstr(str, len) char *str; int len; { while ( *str tt len>0 ) { if ( OutcharCstr) ) return 0,- ++str; —len; ) return 1, ) /* Output a link <LINK HREF=url name> */ static t OutLin lhref.name,title) char *href, 'name, *tιtle, { if ( href'=NULL ) { if ( ioutst("<LINK HREF=")) return! 0 ), if ( !outstr(href) ) return! 0 ) ,- if ( !outch)' ')) return! 0 ),- if ( ioutst("REL=" ) ) return) 0 ), if ( 'outst(name) ) return) 0 ), if ( title'=NULL ) { if ( Outch)' ')) return! 0 ), if ( 'outst ("TITLE=") ) return! 0 ), if ( 'outst(title) ) return! 0 ), ) if ( 'outst(">Nn" ) ) return! 0 ); } return 1, ) /* Output all of the stuff in a page's header. If the header is empty then */ /* don't bother. Also output <HTML> and <B0DY> */ static t OutHeader(page,dobase) HtmlPage "page; t dobase, { mt i, if ( 'outst("<HTML>") ) return) 0 ), if ( dobase | | page->style | | page->tιtle | | page->otherlιnks | | page->upl | | page->base | | page->ιsιndex ) { if ( 'outst("<HEAD>Nn") ) return) 0 ),- if ( page->tιtle ) { if ( 'outst("<TITLE>") ) return) 0 ), if ( 'outstr(page->tιtle) ) return) 0 ), if ( 'outs ("</TITLE>Nn" ) ) return) 0 ), ) if ( 'OutLink(page->style, "STYLE" ,NULL) ) return! 0 ), /*ιf ( 'OutLink)page->docname, "DOCUMENT" .NULL) ) return) 0 ) , */ if ( 'OutLink(page->upl, "UP" ,page->uptιt) ) return! 0 ), if ( page->otherlιnks ) { for ( ι=0; page->otherlmks[l] '=NULL; ++ι ) { if ( 'outst("<LINK ")) return) 0 ), if ( !outstr(page->otherlιnks[i] ) ) return) 0 ); if ( ioutst(">Nn") ) return) 0 ),- } } if ( page->headerιnfo ) { for ( 1=0; page->headerιnfo[l] '=NULL; ++ι ) { if ( loutst ("<")) return! 0 ) ,- if ( ioutst!page->headerιnfo[ι] ) ) return! 0 ), if { ioutst(">Nn") ) return) 0 ) ,- } } if ( page->base | | dobase ) { if ( !outst("<BASE HREF=") ) return! 0 ), if ( page->base ) { if ( 'outstr(page->base) ) return! 0 ), } else if ( Outstr(page->url) ) return) 0 ), lhtml.c Thu Mar 23 17:27:18 1995 16 if ( ioutst(">Nn" ) ) return! 0 ); } if ( page->ιsindex ) { if ( '.outst("<ISINDEX ")) return! 0 ); if ( page->ιιprompt!=NULL tt 'outst(page->ιιprompt) ) return(O); if ( !outst(">Nn" ) ) return! 0 ); ) if ( ioutst("</HEAD>") ) return! 0 ) ; } if ( ioutst("<BODY>") ) return) 0 ),- return 1; } /* Output an isindex form. This is now more complicated than it was because */ /* we need to parse the prompt text to see if we need to save out mcom's */ /* prompt extension to ISINDEX */ static int outismdex(Para *para) { char *ptext = para-> ιrst->post->text; char *pt = strchr(ptext,HTML_MARK) ,- char *def = DEF_ISINDEX_PROMPT; if ( pt==NULL ) return( outst("<ISINDEX>Nn")) ; if ( strlen(def)==pt-ptext tt strncmp(ptext,DEF_ISINDEX_PROMPT,pt-ptext)==0 ) return! outst( "<ISINDEX>Nn")) ; if ( ioutst("<ISINDEX PROMPT=N"")) return 0; if ( !outstn(ptext,pt-ptext) ) return 0, return outs ("N">Nn" ) ; } /* Output a paragraph. There are two cases, a paragraph of paragraphs, and a */ /* paragraph of text. In the former case we run through all the sub-para- */ /* graphs and recurse. In the latter case we go through all the text of the */ /* paragraph and check for nested HTML side. In both cases we precede the */ /* paragraph with its HTML mark (<P>, <H1>, <LI>, ..) and follow with its */ /* terminator */ static int OutPara(page,para) HtmlPage 'page; Para 'para; { unsigned char *str, struct keyparse "nesting[500] ; t nest=0, middocrlfs; t len, tag; t prιnted__p = 1; Para *np; while ( para '= NULL ) { if ( para->tag==FORM_TAG tt para->isindex ) { /* If it is an auto-generated form then don't output it as such */ /* if the isindex was in the header (where t should be) then do */ /* nothing, else put out an ISINDEX in the body (here) */ if ( !page->ιsιndex tt 'outιs dex(para) ) goto failure; goto next_para; ) while (1) { if ( para->tag==PRE_TAG | | para->tag==LISTING_TAG | | para->tag==PLAINTEXT_TAG ) docrlfs = 0, if ( para->tag==P_TAG tt para->fake ) pπnted_p = 0; else if ! para->tag'=P_TAG | | para->tagtext!=NULL | | para->parent==NULL | | para->parent->first '= para || para->parent->tag<PLISTTAG_START || para->parent->tag>PLISTTAG_END ) { if ( !outch('<')) goto failure; if ( 'outs (key2names[para->tag] ->name) ) goto failure; lhtml.c Thu Mar 23 17:27:18 1995 17 if ( para->tagtext'=NULL ) { if ( 'outstr (para->tagtext) ) goto failure, } if ( 'outch('>')) goto failure, prιnted_p = 1, } else prmted_p = 0, if ( para->fιrst==NULL ) break, para = para->fιrst, } if ( para->text '= NULL ) ( middocrlfs = docrlfs, for ( str = (unsigned char *) (para->text) , *str'=' 0'; ++str ) { if ( *str'=HTML_MARK ) { if ( Outchar (*str) ) return) 0 ) } else { len = str[HTML_LEN_HIGH] '256+str[HTML_LEN_L0W] , tag = (unsigned char) st (HTML_POS_TAG] , if ( tag==TEXTAREA_TAG ) docrlfs = 0, if ( tag==END_TAG ) docrlfs = middocrlfs, if (- tag==END_TAG tt nest>0 ) { if ( 'outst ("</") ) goto failure, if ( ' outstr(nesting [—nest] ->name) ) goto failure, if ( Outch) '>')) goto failure, ) else if ( tag==ERROR_TAG ) { /* Skip it */, } else if ( tag==UNKNOWN_TAG ) { if ( 'outch ('<') ) goto failure; if ( Outnstr ( (char * )str+4, len) ) goto failure, if ( Outch) '>')) goto failure, } else if ( key2names[tag] ' =NULL ) { if ( key2names [tag] ->termιnated ) nesting[nest++] = key2names [tag] , if (! tag==INPUT_TAG | | tag==SELECT_TAG | | tag==OPTION_TAG) tt ch_pos'=0 tt docrlfs ) if ( ' outch! ' Nn' ) ) goto failure, if ( 'outch! '<')) goto failure, if ( ' outstr (key2names [tag] ->name) ) goto failure, if ( ' outnstr( (char * ) str+4, len) ) goto failure, if ( 'outch('>')) goto failure; } str += len+3, } } if ( nest'=0 ) IError ( "Nesting level all wonky"), if ( 'outch{ ' Nn' ) ) goto failure; ) if ( prmted_p t docrlfs tt 'outch('Nn')) goto failure, next_para. if ( para->post==NULL ) { while ( para'=NULL tt para->post==NULL ) { if ( para->tag' =P_TAG tt key2names [para->tag] --"terminated) { if ( ioutst ("</") ) goto failure, if ( 'outst (key2names [para->tag] ->name) ) goto failure; if ( 'outch('>') ) goto failure, } para = para->parent. } if ( para==NULL ) break,- docrlfs = ' ParaPreformatted(para) , } if ( para->tag ' =P_TAG tt key2names [para->tag] ->termιnated) lhtml.c Thu Mar 23 17:27:18 1995 18 if ( ioutst("</") ) goto failure; if ( ioutst(key2names[para->tag]->name) ) goto failure; if ( ioutch! '>' ) ) goto failure; ) para = para->post; } docrlfs = 1; return 1; failure: docrlfs = 1; return 0; } /* Output one page of HTML, first doing its header then its body (paragraphs) */ static int OutHt lPage(page, obase) HtmlPage *page; int dobase; { Para *para; ch_pos = 0; if ( !OutHeader(page,dobase) ) return 0; if ( !OutPara(page,page->first) ) return 0; if ( outst("</BODYx/HTML>Nn") ) return 0; return 1; ) static int write_null PROTOTYPE ((void *foo, int bar)) { IErrorCbad writer state! "),- return EOF; ) int WriteHtmlPage(page, dobase, func, context) HtmlPage *page; int dobase; int Cfunc) (voi d *,int); void 'context; { int ret; outfunc = func; outctx = context; ret = OutHtmlPage(page, dobase); outfunc = write_null; outctx = (void *)0; return ret; } int WriteHtmlBody(page, func, context) HtmlPage 'page; int Cfunc) (void *,int); void *cont ext; { int ret = 1; Para *para; outfunc = func; outctx = context; ret = OutPara(page,para->first) ; outfunc = write_null; outctx = (void *)0; return ret; } /* Output a page to a file */ int XVT_CALLC0NV1 HtmlPage2File(page,filename,dobase) char 'filename; HtmlPage "page; int dobase; { •if defined(macintosh) FILE "output = fopen(filename, "wb") ,- •else FILE *output = fopenlfilename, "w" ) ; •endif int ret; if (output == NULL) return -2; lhtml.c Thu Mar 23 17:27:18 1995 19 ret = WriteHtmlPage(page,dobase, (mt (*) (voιd *, int) IWriteFile,output) , fclose( output ), return! ret ) , } /* Convert a page to HTML and store the result in a string We return the */ /* string, but the caller is not allowed to free it */ /* why not' it looks like the caller should */ char * XVT_CALLCONVl HtmlPage2Str(page,dobase) HtmlPage 'page, int dobase { t ret, strctx sc, sc.bpos = 0, sc.blen = 0, sc.body = (char *)0; ret = WriteHtmlPage(page,dobase, lint CMvoid *,int) )WriteStr,tsc) , if ( 'ret ) return( NULL ) ; sc body[sc.bpos] = 'NO', return! sc.body ), ) int XVT_CALLC0NV1 HtmlPage2UR (page,url) HtmlPage 'page char *url, ( return -2, } static int Cmfunc) (void *), static void *ιnctx, static int haspeek, static mt peekch, •if Dbg_Test static FILE 'dump, •endif /* Low level input routine for one character No interpretation is placed on */ /* the character */ static mt inch)) { int ch, if(haspeek) { haspeek = 0, return peekch, } if ( ( ch = mfunc(mctx) )==HTML_MARK ) ch = ''' ; •if Dbg_Test if ( dump'=NULL ) fputc(ch,dump) , •endif return ch, } /* Back up one character (backed up characters will still be interpretted) */ /* at most one character may be backed up */ static int ungetch(ch) mt ch, { haspeek*+, peekch = ch,- return 1, } /* Back up one character (backed up characters will not be interpreted, but */ /* will be treated litterally) There is no maximum on how much we may back */ static int ungetchr(ch) int ch, { if ( ch==EOF ) lhtml.c Thu Mar 23 17:27:18 1995 20 return( 1 ) ; if ( rmax>=rlen ) { rlen += 1000; if (( ungot = (unsigned char *) myrealloc( (char *) ungot,rlen)) == NULL ) return 0; } ungot[πt_ax++]= ch; return 1; } •ifdef debug static void reporterror(err) int err; { switch ( err ) { case HTM_ERR__BADAMP: _html_error("t followed by an invalid"escape sequenceNn" ), brea k; case HTM_ERR_NOGT: _html_error("A termination tag had attπbutesNn" ),- break; case HTM_ERR_MISTAG: _html_error("A termination tag did not match the opening tag it should haveNn" ) ; brea ; case HTM_ERR_TAGEOF: _html_error("An EOF was read before the closing >Nn" ); break; case HTM_ERR_ATTRS: _html_error!"An attribute was given to a tag which has noneNn" ), break, case HTM_ERR___ADATTR: _html_error( "A bad attribute was given to a tagNn" ); break; case HTM_ERR_NOQUOTE: _html_error("No closing quote for an attribute's valueNn" ); br eak; case HTM_ERR_NOVALUE: _html_error("No value given for attribute that needs oneNn" ) ,- break; case HTM_ERR_BADVALUE: _html_error( "Value given for attribute that shouldn't have one Nn" ) ; break; case HTM_ERR_BADHEADE : _html_error("Body item found in headerNn" ) ; break; case HTM__ERR_BADBODY _html_error("Header item found in bodyNn" ) ; break; case HTM_ERR_TRAILCH _html_error("Characters found after page endNn" ),- break; case HTM_ERR__BADNEST _html_error("Some tags not closedNn" ) ; break; case HTM_ERR_TAGINTITLE: _html_error("Tag withm a title tagNn" ) ; break; case HTM_ERR_BADTAGINBODY. _html_error("HEAD, BODY, or HTML tag found inside BODYNn" ) ; break; default: _html_error("Unknown error %dNn" , err ) ; break; ) ) •endif /* Push an error flag back onto the input stack */ static void ungeterr(page,err,arg,pushmark) HtmlPage *page; int err.arg, pushmark; { ungetchr(arg) ; ungetchr(err%256) ,- ungetchr(err/256) ,- ungetchr(ERROR_TAG) ; ungetchr(3) ; ungetchr(0) ; if ( pushmark ) ungetchr(HTML_MARK) ; •ifdef debug reporterror(err) ,- •endif page->haderrors = true; } static void addheadererr(page,err,arg) HtmlPage 'page; mt err, arg; { int l; 1 = 0; if ( page->headererrs!=NULL ) for ( ,- page->headererrs[i] '='N0' ; -+i ); page->headererrs = (short *) myrealloc( (char *) page->headererrs, d+2)'sizeofCpage->h eadererrs) ) ; page->headerargs = (char *) myrealloc( {char *) page->headerargs, (i+2)'sizeofCpage->he lhtml.c Thu Mar 23 17:27:18 1995 21 aderargs) ) ; if ( err'=0 ) { page->headererrs[I]= err, page->headerargs[I]= arg, •ifde debug reporterror(err) ; •endif } else { page->headererrs[I] = ιnchr()*256, page->headererrs[I] += inchr() , page->headerargs[i] = inchrO; ) page->headererrs[l+lj = 'NO', page->headerargs[l+l) = 'NO', page->haderrors = true; } static void addtrailerr(page,err,arg) HtmlPage "page, t err.arg, ( ι = 0, if ( page->traιlerrs'=NULL ) for ( ; page->traιlerrs[I] '=' O' , ++ι ), page->traιlerrs = (short *) myrealloc( (char *) page->traιlerrs, (ι+2)"sizeof(*page->tra llerrs) ) , page->traιlargs = (char *) myrealloc( (char *) page->traιlargs, (ι+2) "sizeof(*page->head erargs) ) ; if ( err'=0 ) { page->traιlerrs[i]= err; page->traιlargs[i]= arg, •ifdef debug reporterror(err) ; •endif } else { page->traιlerrs[i] = ιnchr()*256; page->traιlerrs[l] += inchr() , page->traιlargs[I]= inchrl), } page->traιlerrs[l+l] = 'N0',- page->traιlargs[i+l] = 'NO', page->haderrors = true, ) /* Push an end flag back onto the input stack */ static void ungetend(tag) t tag; { ungetchr(tag) ; ungetchr(END_TAG) ; ungetchr(1) ; ungetchr(0) , ungetchr(HTML_MARK) ; } /* Push a tag onto the stack after we read one too far */ static void ungettagttag,len) mt tag, len; { ungetchr(tag) ; ungetchr(len%256) ; ungetchr(len/256) ; ungetchr(HTML_MARK) ; } static t slurptagO { mt ch, tpos=0, len, while ( (ch=ιnch() ) '='>' tt ch'=EOF ) { lhtml.c Thu Mar 23 17:27:18 1995 22 if ( tpos>=tmax ) tagbuf = myrealloc (tagbuf,tmax += 400); tagbuf[tpos++]=ch; } if ( ch==EOF ) ungeterr(page,HTM_ERR_TAGEOF,nesting[nlevel-1] .true) ; len = tpos; while ( tpos>0 ) ungetchr(tagbuf[—tpos] ) ; return(len) ,- static char *slurpTagText(len) int len; { mt tpoε=0; if ( len<=0 ) return(NULL) ; if ( len>=tmax ) tagbuf = myrealloc(tagbuf,tmax = len+400); while ( --len>=0 ) tagbuf[tpos++]=ιnchr( ) ; tagbufItpos]='NO' .- return(copy(tagbuf) ) ; } static void newnest(tag) int tag; ( if ( nlevel>=nmax ) { nesting = (int *) myrealloc( (char *) nesting, (nmax+=100) "sizeof (at) ) , nestoff = (int *) myrealloc( (char *) nestoff, (nmax+=100)'sizeof(int) ) , ) nestoff[nlevel] = -1; nesting[nlevel++] = tag; ) static void setnestofflint off, mt tag) { mt i, for ( ι=nlevel-l; nestoff[l]==-1; --1 ) ; for ( ++1 ,- Knlevel tt nesting[i] '=tag; ++ι ), if ( ι>=nlevel ) IErrorCNest offset quite wrong"); else if ( nesting[i] !=tag ) IErrorCNest offset: Can't find right tag"); else nestoff[i] = off; } /* Input a character of the form &#xx; where x is a hex digit */ /* These characters are said to be in latinl, so if we are not running under */ /* X we must convert the letter into a character name (by looking it up in */ /* the lat l chamame table) and then convert the name back into the current'/ /* character set */ static int indec() { mt ch, resch, i; resch = 0; while (<ch = inch())!=EOF tt isdιgιt(ch) ) { resch = 10*resch + (ch-'0'); ) if ( ch!=' ; ' ) ungetch(ch) ; if ( charr_ames==latιnlcharnames ) return( resch ) ; lhtml.c Thu Mar 23 17:27:18 1995 23 for ( ι=0; latinlcharnames[l] .name'=NULL tt latinlcharnames[i] ch!=resch; ++ι ) if ( latinlcharnames[l] .name==NULL ) /* Can't find it */ return( resch ) ; l = charsearch(latinlcharnames[l] .name! , if ( ι'=-l ) resch = charnames[i].ch; return( resch ) ,- } /* Check to see if we use any of mcom's extensions */ static void checkformcom(tag,len) int tag,len; { char buffer[50] ; if ( tag==NOBR_TAG | | tag==WBR_TAG | | tag==FONT_TAG | | tag==BASEFONT_TAG | | tag==CENTER_TAG ) page->mcomextensιons = true, else if ( len'=0 tt (tag==ISINDEX_TAG | | tag==HR_TAG || tag==UL_TAG tag==OL_TAG | | tag==LI_TAG | | tag==BR_TAG ) ) page->mcomextensιons = true; else if ( 'page->mcomextensions tt tag==IMG_TAG tt len'=0 ) ( parseAttrs (page,IMG_TAG,tagbuf,len, false) , if ( ιmg_lιst[4] .len'=0 | | ιmg_lιst [5] .len'=0 | | ιmg_lιst[6] .len'=0 || ιmg_lιst[7] .len'=0 || ιmg_lιst[8] .len'=0 ) page->mcomextensions = true; else if ( ιmg_lιst[1] .len'=0 ) { strncpy(buffer,ιmg_lιs [1] .val.min(sizeof(buffer) ,ιmg_lιst[1 ■len) ) buffer[sizeof(buffer)-1]='NO' ; if ( ιmg_lιs [1] .len<sιzeof(buffer)-l) buffer[ιmg_lιst[l] .len]='\0' ; if ( strmatchlbuffer, "top") '=0 tt strmatch(buffer, ' bottom" ) '=0 tt strmatchfbuffer, "middle")'=0 ) page->mcomextensions = true; } /* Input one character looking out for special stuff like tquot, or <HTML> */ static mt inchr)) { char buffer[80] ; register int I, s, ch, len, och, anynonp, hadsemi; if ( rmax>0 ) return( ungot[—max] ) , ch = inch() ; if ( foundplam ) /* No interpretation of anything */ return( ch ) ; if ( !ch=='t' tt (nlevel==0 || nesting[nlevel-1] '=LISTING_TAG) ) || ch=='<' ) { 1 = 0; och = ch; hadsemi = false; if ( ch=='t' ) { if (( ch=ιnch())=='#' ) return( mdec() ) ,- while ( ιsalpha(ch) it κsιzeof(buffer)-1) { buffer[ι++] = ch; ch = inch() ; ) if ( ch==' ; ' ) hadsemi = true; } else if ( (ch=mch())=='' ' ) { /* HTML comment. Just eat it for now */ while ( (ch=ιnch() ) '=E0F tt ch'='>' ),- return(inchr() ) ,- } else { lhtml.c Thu Mar 23 17:27:18 1995 24 while ( ch!=EOF tt navi_ιsspace(ch) ) ch=ιnch() if { ch=='/' ) { buffer ++]='/' ,- ch = inch{ ) ; } while (ch!=EOF tt navι_ιsspace(ch) ) ch=ιnch(); while ( ιsalnum(ch) tt κsιzeof(buffer) -1 ) { buffer[i++] =ch; ) ) if ( !hadsemi ) ungetch(ch) ,- /* will be interpreted */ buffer[i]='N0' ; if ( nlevel'=0 tt nesting[nlevel-l]==LISTING_TAG tt och=='<- tt strmatch(buffer, "/LISTING") '=0 ) { for ( i=strlen(buffer)-1 ; ι>=0 ,- --ι ) ungetchr(buffer[i] ) ; ch = '<' ; ) else if ( och=='t' tt (l = charsearch(bu fer) )== -1 ) ( /* Unknown character name, treat as literal t */ if ( hadsemi ) ungetchr(';') ; for ( ι=strlen(buffer)-l ; ι>=0 ; --ι ) ungetchr(buffer[i] ) ; ungetchr( ' ') ; ungeterr(page,HTM_ERR_BADAMP,ERROR_TAG. false) ; ch = HTML_MARK; /* We return this */ ) else if ( och=='t' ) { /* Known character name. Return it, but check to see if we read */ /* too much (tEacutemile must be read as E'mile not as E' ) */ •ifdef debug _html_error("character matched t%s with %s (%c)Nn", buffer, charnames[i] .name, charnames[i] .ch) ,- •endif ch = charnames[i] .ch; /* We return this s = strlen(charnames[i] .name)-1; if (( i = strlen(buffer)-l ) >- ) ! if ( hadsemi ) ungetchr!', for ( ; ι>=s; —l ) ungetchr(buffer[i] ) ; } else if (( buffer[0]==' /' tt ( i = htmlsearch(buffer+1) )== - 1 ) (buffer[0] !='/' tt (i = ht lsearch(buffer) )== -1 ) ) { /* Unknown html tag, put whole thing into text */ •ifdef debug _html_error("unknown html tag <%sNn" , buffer ) ; •endif len = slurptagO; for ( =strlen(buffer)-l ; ι>=0 -.-.len ) ungetchr(buffer[i] ) ; ungetchr(UNKNOWN_TAG) ; ungetchr(len%256) ; ungetchr(len/256) ; Ch = HTML_MARK; /' We return this } else if ( buffer[0]=='/' ) { /* Known ending tag */ •ifdef debug _html_error("tag matched <%s with %s (%d) nlevel=%d nest=%dNn" , buffer, keynames[i] .name, keynames[i].html_tag, nlevel, nesting[nlevel •endif while! navi_isspace(ch = inch.))); if ( ch!='>' ) { ungeterr(page,HTM_ERR_NOGT,keynames [I] .html_tag, true) ; lhtml.c hu Mar 23 17:27:18 1995 25 while { ch!=EOF tt ch!='>' ) ch = inch() ,- } anynonp = -1; for ( s=nlevel-l; s>=0 tt nesting[s] !=keynames[i] .html_tag; --s ) if ( nestin [s] !=P_TAG ) anynonp = s; if ( anynonp!=-1 ) ungeterr(page,HTM_ERR_MISTAG,keynames[i] .html_tag,true) ,- if ( s>=0 ) { for ( ; s<=nlevel-l; ++s ) ungetend(nesting[s] ) ,- } ch = inchr() ,- } else if { keynames[i] .html_tag==SP_TAG ) { ch = _C_NBS; inch)); /* throw out > */ } else { /* Known start tag */ if ( keynames[i] .terminated ) newnes (keynames[i] .html_tag) ; •ifdef debug __html_error(" ag matched <%s with %s (%d) nlevel=%d nest=%dNn", buffer, keynames [i] .name, keynames [i].html_tag, nlevel, nesting[nlevel -D); •endif len = slurptagO; if ( !page->mcomextensions ) checkformcom( keynames[i] .html_tag, len ) ,- ungetchr(keynaunes[i] .html_tag) ; ungetchr(len%256) ; ungetchr(len/256) ,- ch = HTML_MARK; /* We return this */ if ( keynames[i] .html_tag==PLAINTEXT_TAG ) foundplain = 1; ) } else if ( ch==HTML_MARK ) /* If there were an HTML_MARK in the file */ ch = inchr(); /* already, ignore it. It'd confuse us. */ return( ch ) ,- } static void skip(len) int len; { while ( --len >= 0 ) inchr() ,- } static int hasListParen (parent) Para *parent; { while ( parent!=NULL ) { if ( parent->tag>=DIR_TAG it parent->tag <= UL_TAG ) return 1; parent = parent->parent; } return 0; } /* Are any of the parent paragraphs preformatted ? */ int ParaPreformatted(para) Para *para; { if I 'nesting!=NULL tt nlevel>0 tt nesting[nlevel-1] == TEXTAREA_TAG ) return true; while ( para!=NULL ) { if ( para->tag == PRE_TAG | | para->tag==LISTING_TAG | | lhtml.c Thu Mar 23 17:27:18 1995 26 para->tag == PLAINTEXT TAG ) return true, para = para->parent; } return false; } static char *slurpwhιte(str, plen) char *str, int *plen, { mt len = *plen; whileden > 0 tt navι_ιsspace(*str) ) { ++str; --len; } •plen = len; return str; } static struct attribs 'parseAttrs(page,tag,str,len,stufferr) HtmlPage "page, int tag, len, stufferr; char *str; { char buffer[80], *pt, int i, hadquote, struct attribs *attr; str = slurpwhιte(str, tlen) ; if ( key2names[tag]==NULL || (attr = key2names[tag]->attr)== none ) { if ( len'=0 tt stufferr) ungeterr(page,HTM_ERR_ATTRS,tag,true) ; return(NULL) ; } for ( ι=0; attr[l] .name'=NULL, ++ι ) { attr[l] .present = 0; attr[ij -len = 0; } while ( len > 0 ) { str = slurpwhite(str, tlen); pt = buffer, while ( len>0 tt isalphaCstr) tt pt<buffer+sizeof(buffer)-1 ) { *pt++ = islowerCstr) 'toupper(*str) :*str, ++str; --len; } if ( pt==buffer ) { /* Prevent infinite loops on bad input */ *pt++ = *str++; —len; ) *pt = 'NO' ; for ( i=0; attr[i] .name'=NULL tt strcm (attr[l] .name,buf er) '=0; ++ι ), if ( attr[ι] .name==NULL ) { if ( stufferr ) ungeterr(page,HTM_ERR_BADATTR,tag,true) ; if ( *buffer==*N0' ) { ++str; --len; } } else attr[ι] .present=l, str = slurpwhite(str, tlen); pt = NULL; if ( attr[i] .name==NULL ) /* Ignore it */; else if ( len>0 tt *str=='=* ) { if ( stufferr tt attr[I] .value==VAL_NONE ) ungeterr(page,HTM_ERR_BADVALUE,tag, rue) ; ++str; —len; pt = str = slurpwhite(str, tlen); lhtml.c Thu Mar 23 17:27:18 1995 27 if ( len>0 tt *str==' " ' ) { hadquote = true; pt = ++str; --len; while ( len>=0 tt *str'='"' ) { ++str; --len; } if ( len<0 tt stufferr ) ungeterr(page,HTM_ERR_N0QU0TE,tag, rue) ; } else { hadquote = false; while ( len>0 tt !navι_ιsspace(*str) ) { ++str; --len; } } if ( attr[ ] .name'=NULL ) { attr[ι].val = pt; attr[ι] .len str-pt, if ( hadquote tt len>0 tt *str=='"' ) ( ++str; --len; } ) else { if ( stufferr tt attr[i] .name'=NULL tt attr[l] .value'=VAL_NONE ) ungeterr(page,HTM_ERR_NOVALUE, ag,true) , } } return! attr ) ; ) static struct attribs "slurpParseAttrs(page,tag,len) HtmlPage "page; mt tag,len; { mt l; if ( len>=tmax ) tagbuf = myrealloc(tagbuf,tmax = len+400) ; for ( ι=0; len>0; tagbuf[ ++]=ιnchrI) , --len ) ,- return! parseAttrs(page,tag,tagbuf,l,true) ) ,- ) static t unnestlpage, len, tag) HtmlPage "page; t len, tag; { if ( len'=l ) IError Bad ending tag"); else if ( mchr() !=tag ) ungeterr(page,HTM_ERR_MISTAG,tag,true) , else if ( nlevel<=0 ) lError("Nesting all screwed up in input"), else { --nlevel,- return 1; } return 0; ) static char *slurp2en (page,tag) HtmlPage "page; int tag; { int i, ch, len; mt nl=nlevel; 1 = 0; keepon for ( , (ch=mchr() ) !=EOF tt ch'=HTML_MARK; ++ι ) ( if ( ι>tmax ) tagbuf = myrealloc(tagbuf, max+=400) ; tagbuf[ι]= ch; } len = mchr() '256; len += chr() ,- lhtml.c Thu Mar 23 17:27:18 1995 28 ch = mchr( ) , if ( ch==ERROR_TAG ) { len = inchr!) "256, len += inchr() , addheadererr(page, len,inchr() ) , goto keepon, } else if ( ch'=END_TAG ) { addheadererr(page,HTM_ERR_TAGINTITLE,ch) , goto keepon, } else if ( ch==END_TAG tt nl<nlevel ) { unnest(page.len,nesting[nlevel-1] ) , goto keepon, } unnest(page,len,tag) , return! copyn(tagbuf,i) ) , ) static void slurpHeadltem(page,tag, len) HtmlPage "page, mt tag, len { struct attribs "attr, char "pt, nt i, char buffer[20] , attr = NULL, if ( tag'=ERROR_TAG ) attr = slurpParseAttrs(page,tag, len) , if ( tag==ISINDEX_TAG ) { page->isindex = true, if ( attr[0] .len==0 ) page->ι prompt = NULL, else page->ιιprompt = copy(tagbuf) , } else if ( tag==BASE_TAG ) { page->baεe = copynlattr[0] .val ,attr[0] .len) , } else if ( tag==LINK_TAG ) { char *href=NULL, *tιtle=NULL, int found = 0, for ( ι=0; attr[l] .name'=NULL, ++ι ) { if ( attr[i] .present ) { if ( strcmpfattr[l] .name "HREF")==0 ) href = copynlattr[i] .val,attr[i] .len) , else if ( strcmp!attr[l] .name, "TITLE" )==0 ) title = copynlattr[l] .val,attr[l] .len) , else if ( href'=NULL tt (strcmp(attr[l] .name, "REL")==0 | | strcmp(attr[i] .name, "TYPE")==0 )) { strncpy(buffer,attr[i] .val,mιn(sιzeof(buffer) ,attr[ ] len) ) , bufferlsizeof(buffer)-1]='NO' , if ( attr[i] .len<sιzeof(buffer)-1 ) buffer[attr(i] .len]='N0' , if ( strcmplbuffer, "UP")==0 ) { page->upl = href; found = 1, page->uptιt = title, ) else if ( strcmp(buffer, "DOCUMENT")==0 ) { page->docname = href, found = 1, } else if ( href'=NULL tt strcmp(buffer, "STYLE")==0 ) { page->style = href, found = 1 } } } } if ( 'found ) { /* Not one of ours */ for ( pt=tagbuf, len>0 tt navι_ιsspaceCpt) , ++pt) —len, if ( len>0 ) { lhtml.c Tfau Mar 23 17:27:18 1995 29 i = 0; if ( page->otherlinks!=NULL ) for ( ; page->otherlinks[i] !=NULL; ++i ) ; page->otherlinks = (char **) myrealloc( (char *) page->otherlinks, (i+2)*siz eof(char *) ) ; page->otherlinks[i] = copyn(pt,len) ; page->otherlinks[i+1] = NULL; if ( href!=NULL ) myfree(href) ,- } ) } else if ( tag==TITLE_TAG ) { page->title = slurp2end(page,tag) ; } else if ( tag==UNKNOWN_TAG ) { i = 0; if ( page->headerinfo!=NULL ) for ( ; page->headerinfo[i] !=NULL; ++i ) ; page->headerinfo = (char ") myrealloc( (char *) page->headerinfo, (i+2) 'sizeof(char *)) ; page->headerinfo[i] = copynt agbuf,len) ; page->headerinfo[i+l] = NULL; /* experimental */ } else if ( tag==REFRESH_TAG ) { char *num = copynlattr[0] .val,attr[0] .len) ; page->refresh = atol(num); myfree(num) ; / « experimental */ } else if ( tag==ERROR_TAG ) addheadererr(page, 0,ERROR_TAG) ; } static void slurpHeader(page) HtmlPage 'page; { int ch, len, tag; int nl = nlevel; for (;;) { while ( (ch=inchr() ) !=E0F tt navi_isspace(ch) ) ; if ( ch!=HTML_MARK ) break,- len = inchr() '256; len += inchr() ,- tag = inchr() ; if ( tag==END__TAG ) { /* End header */ if ( iunnest(page,len,HEAD_TAG) ) continue; return; } if ( tag==UNKNOWN_TAG | | tag==ERROR_TAG | | tag==LINK_TAG | | tag==ISINDEX_TAG | | tag==BASE_TAG | | tag==TITLE_TAG ) slurpHeadltem(page,tag,len) ,- else if ( tag==BODY_TAG ) { addheadererr(page,HTM_ERR_BADHEADER,B0DY_TAG) ; ungettagftag,len) ,- —nlevel; retur ; } else { ungettagftag,len) ; ch = inchr() ; break; ) } ungetchr(ch) ; addheadererr( age,HTM_ERR_BADHEADER,ERR0R_TAG) ; nesting[nl-l]= BODY_TAG; lhtml.c Thu Mar 23 17:27:18 1995 30 return; } /* Terminate all outstanding tags above basenl, and pop them off the stack */ static int end2base(basenl,l,tag) long basenl, I,tag; { int pushtag=0; int ntag; lf ( nlevel>basenl tt nesting[nlevel-1]==tag ) { pushtag = 1; --nlevel; } while ( nlevel>basenl ) { ntag = nesting[--nlevel] ; if ( ntag<PARA_START | | ntag>PARA_END ) { if ( ι+5 >= pmax ) pbuf = myrealloc(pbuf,pmax += 5* (nlevel-basenl) ) ; pbuf[l++]= HTML_MARK; pbuf[ι++]= 0; pbuf[ι++]= 1, pbuf[ι++]= END_TAG; pbuf[ι++]= ntag; } } if I pushtag ) nesting[nlevel++] = tag, return(l) ,- ) /* We pretend that seperate lines of a <PRE> paragraph are seperate paras */ /* we do that to avoid the 64k limit which we run into on big <PRE>s (ie a */ /* whole file in one <PRE>) . But this means we must terminate all the tags */ /* at the end of each line, and then restart them */ /* This routine is similar to the above but it does not pop stuff ended */ static long endtagsllong pi, mt fromnl ) { t nlε, len; len = (nlevel-fromnl-1) * HTML_END_LEN, if ( pi+len >= pmax ) { •ifdef MEMORY_MASK if ( pmax+4000L+len > MEMORY_MASK ) pmax = MEMORY_MASK, else •endif pmax += 4000+len; if ( pι+len+2>pmax ) return( pi ) ; pbuf = myrealloc(pbuf,pmax) ; } for ( nls=nlevel-l; nls>fromnl; —nls ) { pbuf[pi++] = HTML_MARK; pbuf[pι++] = 0; pbuf[pi++] = 1; pbuf[pι++] = END_TAG; pbuf[pι++] = nesting[nls] ; } pbuf[pi]='NO' ; return pi; } /* See above comment */ static long restarttags (long pi, int fromnl, mt topnl, char "oldstr ) { int nls, len, oldoff; char *p ; lhtml . c Tbu Mar 23 17 : 27 : 18 1995 31 if ( oldstr==NULL | | fromnl>=topnl ) return 0 ; len = 0, if I topnl>nlevel ) topnl = nlevel; for ( nls=fromnl+l ; nls<topnl, ++nls ) len += HTML_HEAD_LEN + i (unsigned char *) oldstr) [nestoff[nls] +HTML_LEN_HIGH] *256 + ((unsigned char *) oldstr) [nestoff [nls) +HTML_LEN_ OW] ; if ( pi+len >= pmax ) { •ifdef MEMORY_MASK if ( pmax+4000L+len > MEMORY_MASK ) pmax = MEMORY_MASK; else •endif pmax += 4000+len, if I pι+len+2>pmax ) return! pi ) ; pbuf = myrealloc (pbuf,pmax) , } for I nls=fromnl+l; nls<topnl; ++nls ) { pt = oldstr + nestoff [nls] , len = HTML_HEAD_LEN + ((unsigned char *) pt) [HTML_LEN_HIGH' *256 + ( (unsigned char • ) pt) [HTML_LEN_LOW] , oldoff = pi ; while ( --len >= 0 ) pbuf[pι++] = *pt++; nestoff [nls] = oldoff; } pbuf [pi] =' NO' ; nestoff [topnl] = -1; return pi ; } /" We got an ISINDEX tag, we need to turn it into a form */ static void makeSearchFormlpage.para) Para "para; HtmlPage "page, { char buffer [600] , char "pt, char 'pad, char *oldtag = para->tagtex , char *prompt; para->tag = F0RM_TAG; para->pnum = pnum++,- if (page->url) { strcpy(buffer, "ACTION=" ) , strcat (buffer, (pt=strrchr (page->url, ' / ' ) ) ' pt+1 page->url) ; ) else { buffer[0] = 'NO'; } para->tagtext = copy(buffer) , para->fιrst = (Para *) myalloc (sizeof (Para) ) ; para->fιrst = (Para *) myalloc (sizeof (Para) ) ; para->fιrst->tag = P_TAG; para->fιrst->pnum = pnum++ ; pad = "brekhead TYPE=TEXT NAME=ISINDEX" ; prompt = NULL; if ( oldtag' =NULL tt HTML_HasAttrStr (oldtag, ISINDEX TAG, buffer, sizeof (buffer) , "PROMPT" )) prompt = buffer, if ( prompt==NULL ) prompt = DEF_ISINDEX_PROMPT, lhtml.c Thu Mar 23 17:27:18 1995 32 para->fιrst->tlen = strlen(prompt)+strlen(pad)+2*HTML_HEAD_LEN, para->fιrst->tmax = para->fιrst->tlen+l; para->fιrst->text = myalloc(para->fιrst->tmax) , HTML_FιllTag(para->fιrst->text,HR_TAG) , strcpy(para->fιrst->text+HTML_HEAD_LEN,prompt) , strcat(para->fιrst->text+HTML_HEAD_LEN,pad) . HTML_FιllTag(para->fιrst->text+para->fιrst->tlen-HTML_HEAD__LEN,HR_TAG) , pt = strstr(para->fιrst->text+HTML__HEAD_LEN. "brekhead") ; HTML_FιllTag(pt,BR_TAG) , pt[HTML_HEAD_LEN]=HTML__MARK, pt[HTML_HEAD_LEN+HTML_LEN_HIGH]='NO' , pt[HTML_HEAD_LEN+HTML_LEN_LOW]=para->fιrst->tlen-HTML_HEAD_LEN- (pt+8-para->fιrst->text) ; p [HTML_HEAD_LEN+HTML_POS_TAG]=INPUT_TAG, para->fιrst->parent = para; para->ιsιndex = true; } static Para 'slurpFigureNewPara(HtmlPage 'page. Para 'parent, Para 'para, t preparent, nt fake, mt basenl) { int ch, len, tag, isindex, char Oldtext , retry ch = mchr ( ) ; isindex = 0 , i f I ! preparent ) while ( ch ' =EOF tt navι_ιsspace ( ch) ) ch = mchr ! ) if ( ch==HTML_MARK ) { len = mchr ! ) * 256 , len += inchr ( ) ; tag = inchr ( ) ; } i f ( para ' =NULL tt para->f ιrst==NULL tt (para->tag==LI_TAG | | para->tag==DD_TAG | | para->tag==DT_TAG | | para->tag==PRE_TAG | | para->tag==ADDRESS_TAG | | para->tag==BLOCKQUOTE_TAG ) ) { para-> fιrst = ( Para * ) myalloc ( sizeof ( Para ) ) , para-> f ιrst->tag = P_TAG , para- >f ιrst->parent = para , para->f ιrst->pnum = pnum++ , para->f ιrst->f ake = para->tag==PRE_TAG; } i f ( ch==EOF ) { return (para ) , ) else i f ( ch ' =HTML_MARK ) { tag = P_TAG , len = 0 , i f ( nlevel==basenl ) newnes t ( P__TAG ) , else nesting[basenl] = P_TAG, ungetchr(ch) , } else if ( tag==END_TAG ) { /* Terminate final <LI> within <UL> */ if ( parent'=NULL tt parent->tag'=nestιng[nlevel-l] tt parent->parent'=NULL tt parent->parent-> ag == nesting[nlevel-1] ) { ungettag(tag,len) , return(para) ; ) if ( 'unnest(page,len,nesting[nlevel-1] ) || nlevel>=basenl ) goto retry; return(para) ; } else if ( (tag<PARA_START || tag>PARA_END) tt tag'=PLAINTEXT_TAG ) { ungettagftag, len) , lhtml . c Thu Mar 23 17 : 27 : 18 1995 33 i f ( i TagNeedsTermma or ( tag) ) { if ( nlevel==basenl ) newnest (P_TAG) ; else nesting[basenl] = P_TAG; ) else if ( nlevel==basenl+l ) { /* First time through, no pushed tags */ newnest (P_TAG) ; nesting [nlevel-1] = nesting[nlevel-2] ,- nesting[nlevel-2] = P_TAG; } else if ( nlevel==basenl ) newnest (P_TAG) ; else nesting[basenl! = P_TAG; tag = P_TAG, len = 0; } else if ( ihasListParent (parent) tt (tag==DD_TAG | | tag==DT_TAG | | tag==LI_TAG )) { /* Can't handle these here, pretend they are normal paragraphs */ fake = false; nlevel = basenl; tag = P_TAG; len = 0; newnest (P_TAG) ; } else if ( parent! =NULL tt ( parent->tag==DD_TAG | | parent->tag==DT_TAG | | parent->tag==LI_TAG ) tt (tag==DD_TAG I I tag==DT__TAG | | tag==LI_TAG | | tag==DL_TAG j I tag==UL_TAG | j tag==OL_TAG ) ) { ungettag (tag, 1en) ,- return(para) ; } else if ( tag==ISINDEX_TAG ) { /* Convert to form */ isindex = 1; } else if ( tag>=HEAD_START tt tag<=HEAD_END ) { slurpHeadltemtpage, tag, len) , goto retry; } else { fake = false; if ( nlevel>basenl+l ) { /* Don't do this for <LI>s which don't need term ators */ nesting[basenl] = nesting [nlevel-1] ; nlevel = basenl+1, } } if ( para==NULL ) para = (Para *) myalloc (sizeof (Para) ) ; else { para->post = (Para *) myalloc (sizeof (Para) ) ,- para = para->post; } para->pnum = pnum++; para->parent = paren ; para->tag = tag; para->tagtext = slurpTagText (len) ,- para->fake = fake; lf ( isindex ) { /* Convert a simple ISINDEX to a form */ --pnum; /* We reassign this within makeSrchFr */ oidtext = para->tagtext,- makeSearchForm(page,para) ; myfree(oidtext) ; goto retry; } return( para ) ,- } lhtml.c Tfau Mar 23 17:27:18 1995 34 /* This overly complex routine parses HTML into a list of paragraphs */ /* Some kinds of paragraphs (BLOCKQUOTES, PREformatteds, etc) are themselves *,' /* 3ust lists of paragraphs. Other kinds (Listltems, DescritionTerms, etc) */ /* cannot themselves occur in a paragraph list, so if they do then either we */ /* terminate the list (if we are inside a UL.OL or DL) or pretend we saw a P */ /* if we aren't. If the paragraph does not begin with anything then pretend */ /* it began with a <P>. */ static Para *slurpParaLιst(page,parent) HtmlPage *page; Para 'parent; { Para *para=NULL, *lιst=NULL, *res; int ch, tag, len, j, basenl, topnl=0, ignore; long i; long resi, respm; char *oldparastr=NULL; int preformatted; int fake = false; t preparent=0; t tag_to_push; static int spl_nestιng; if ( parent!=NULL ) preparent = ParaPreformatted(paren ) ; basenl = nlevel; ++spl_nesting; while ( (ch=inchr()) !=EOF tt !preparent tt navι_ιsspace(ch) ) ; ungetchr(ch) ; else { len = mchr!) '256; len += inchr( ) ; tag = inchr() ; if I basenl>0 tt nesting[basenl-1]==tag it basenl==nlevel ) --basenl; ungettag(tag,len) ; } for (;;) { if ((res = slurpFigureNewPara(page,parent,para,preparent, fake,basenl))==para ) { --spl_nes ing; return( list ) ; ) else if I lιst==NULL ) list = res; para = res; fake = false; if < para->tag>=PARA__START tt para->tag<=PLISTTAG__END tt spl_nestιng<100 ) { /* This will take a list of paragraphs */ para->fιrst = slurpParaLis (page,para) ; } else { preformatted = ParaPreformatte (para) ; i = 0; if ( para->fake ) ι=restarttags (0,basenl,topnl,oldparastr) ,- topnl = basenl; tag_to_push = -1; ch = inchr( ) ; while ( ch!=EOF tt navι_ιsspace(ch) tt ! (preformatted || (nlevel>0 tt nesting[nlevel-l]==TEXTAREA_TAG) ) ) ch = mchr() ; for ( ; ; ) { if ( ch==EOF ) break; if ( ch=='Nn' tt preformatted tt (nlevel<=0 | | (nesting[nlevel-1] !=TEXTAREA_TAG tt nesting[nlevel-1]'=SELECT_ TAG) ) ) { fake = true,- lhtml.c Thu Mar 23 17:27:18 1995 35 l = endtags II, basenl) ; topnl = nlevel; break; } •ifdef MEMORY_MASK f ( 1>MEMORY._MASK-1500 break; •endif len = 0, ignore = 0; if I ch==HTML_MARK ) { len = inchr () *256 ; len += inchr () ; tag = inchr ( ) ,- if ( nlevel==basenl+l tt tag == END_TAG ) { ungetchr(tag = inchrO); f ( tag==nestιng[nlevel-l] ) if ( unnest (page, len,nesting [nlevel-1] ) ) break,- ) else if ( tag == END_TAG ) --nlevel; if ( ( tag>=PARA__START tt tag<=PARA_END ) | | tag==ISINDEX_TAG ) / ♦ We did not terminate the previous paragraph, but */ /* got a new one. This implies termination */ tag_to_push = tag; break; } if ( tag>=HEAD_START tt tag<=HEAD_END ) { slurpHeadltem(page, tag, len) ; ignore = 1 ; } else if ( tag>=HTML_TAG tt tag<=HEAD_TAG ) { skip(len) ; ungeterr (page, HTM_ERR_BADTAGINBODY, tag, true) , --nlevel; ignore = 1 ; } } if I 'ignore ) { if ( ι+len+3>=pmax ) { •ifdef MEMORY_MASK if ( pmax+4000L+len > MEMORY_MASK pmax = MEMORY_MASK; else •endif pmax += 4000+len; pbuf = myrealloc (pbuf,pmax) , if I ι+len+3>=pmax ) { ungettagltag, len) ; ungeterr (page,HTM_ERR_TOOBIG,ERROR_TAG, rue) ; break; ) } pbuf[ι++] = ch; if ( ch==HTML_MARK ) { if ( TagNeedsTerminator(tag) ) setnestoff d-1 , tag) , pbuf[ι++] = len/256; pbuf[ι++] = len%256; pbuf[ι++] = tag; for ( 3=0; 3<len; ++3 ) pbuf[ι++] = mchrl); } } ch = inchr ( ) ; if ( ch'=EOF tt navι_ιsspace(ch) tt /* Multiple spaces to 1 */ ' (preformatted | | (nlevel>0 tt nesting[nlevel-1] ==TEXTAREA_TAG) ) ) { lhtml.c Thu Mar 23 17:27:18 1995 36 while ( ch'=EOF tt navι_ιsspace(ch) ) ch = inchr() ; ungetchr(ch) ; ch = ' ' ; ) } if ( nlevel!=basenl tt 'fake ) { /* For various reasons we may have popped out without closing*/ /* open tags. Do so now */ i = end2base(basenl,ι,tag_to_push) ,- if { tag_to_push>=0 ) ungettag(tag_to_push,len) ; } if I ι>=pmax ) { •ifdef MEMORY_MASK if ( pmax+4000L+len > MEMORY_MASK ) pmax = MEMORY_MASK; else •endif pmax += 4000+len; pbuf = myrealloc(pbuf,pmax) ,- ) pbuf[ι]='N0' ; para->text = oldparastr = copyn(pbuf, I) , para->tlen = I, para->tmax = l+l, ) } --spl_nestιng; /* xvt_app_process_pendιng_events() ; */ } static Para "slurpList(page,paren ) HtmlPage "page; Para "parent; { Para *para=NULL, *lιst=NULL, mt ch, tag, len = 0; mt cnt=0,- int basenl = nlevel; for I basenl=nlevel; basenl>0; —basenl ) if ( nesting[basenl-1]==parent->tag ) break,- for (,;) { while) (ch=mchr()) '= EOF tt navι_ιsspace(ch) ) , if ( ch==EOF ) break, tag = LI_TAG; if ( parent->tag==DL_TAG ) tag = (cnttl)?DD_TAG:DT_TAG; if I ch==HTML_MARK ) { len = mchr()*256; len += mchr() ; tag = mchr() ; if ( tag==LI__TAG tt parent->tag==DL_TAG ) tag = (cnttl) ?DD_TAG:DT_TAG; else if (( tag==DD_TAG || tag==DT_TAG ) tt parent->tag!=DL_TAG tag = LI_TAG; else if ( tag==DD_TAG | | tag==DT_TAG | | tag==LI_TAG ) /* It's all happy and nice */; else if ( tag==END_TAG tt unnest(page, len,parent->tag) ) break,- else ungettag(tag, len) ; ) else ungetchr(ch) ; if I tag==DD_TAG ) cnt |= 1, if ( para==NULL ) lhtml.c Thu Mar 23 17:27:18 1995 37 list = para = (Para *) myalloc (sizeof(Para) ) ; else { para->post = (Para *) myalloc (sizeof (Para) ) ; para = para->post; } if ( tag!=DD_TAG ScSc tag!=DT_TAG tt tag!=LI_TAG ) { tag = parent->tag!=DL_TAG?LI_TAG: (cnttl) ?DD_TAG:DT_TAG; len = 0; } para->tag = tag; para->pnum = pnum++; if ( leni=0 ) para->tagtext = slurpTagText (len) ; para->parent = parent; para->first = slurpParaList (page,para) ; ++cnt,- if ( basenl>nlevel ) break; } return) list ) ; } static void slurpBody(page) HtmlPage *page; { int ch, tag, len, found=0; do { ch = inchr ( ) ; } while ( navi_isspace(ch) ) ; if { ch==HTML_MARK ) { len = inchr(1*256; len += inchr( ) ,- tag = inchr( ) ; if ( tag==END_TAG ) { unnest (page, HTML_TAG, len) ,- return; } else if ( tag!=B0DY_TAG ) ungettag(tag, len) ; else { found = 1; skip(len) ; } } else ungetchr (ch) ; if ( Ifound it (nlevel==0 | | nesting[nlevel-1] ! =BODY_TAG) ) { newnest (BODY_TAG) ; if ( nlevel>2 ) { nesting[nlevel-l] = nesting[nlevel-2] ; nesting[nlevel-2] = BODY_TAG; } } page-> irst = slurpParaLis (page,NULL) ; ) static HtmlPage *slurpHtmlPage(pg) HtmlPage *pg; { int ch, tag, len, done=0, found=0; Para *para; page = pg; pnu = 0; while ( (cb=inchr ( ) ) != EOF tt navi__isspace(ch) ) ,- if [ ch==HTML_MARK ) { len = inchr()*256; len += inchr ( ) ; tag = inchr( ) ,- lhtml.c hu Mar 23 17:27:18 1995 38 if ( tag'=HTML_TAG ) ungettagItag,len) ; else { skip(len) ; found = 1; ) while( (ch=ιnchr() ) '= EOF tt navι_ιsspace(ch) ) ,- } if ( 'found ) { newnest(HTML_TAG) ; if ( nlevel>l ) { nesting[nlevel-1] = nesting[nlevel-2] ; nestin [nlevel-2] = HTML_TAG; } } if ( ch==HTML_MARK ) { len = inchr()*256; len += mchr() ; tag = inchr() ; if ( tag==END_TAG tt unnest(pg,len,HTML_TAG) ) done = true; else if ( tag'=HEAD_TAG ) ungettag(tag,len) ; else skip(len) ; slurpHeader(pg) ; } } else ungetchr(ch) ; if ( idone ) slurpBody(pg) ; while( (ch=mchr0) '= EOF tt navι_ιsspace(ch) ) ,- if I idone ) { if ( ch==HTML_MARK ) { len = ιnchr()*256; len += inchr() ; tag = mchr() ; if ( tag==END_TAG tt unnest(pg,len,HTML_TAG) ) /* Good */; else ungettag(tag,len) ; } else ungetchr(ch) ; } while( (ch=ιnchr()) '= EOF it navι_ιsspace(ch) ) ,- while ( ch==HTML_MARK ) { len = inchr()*256; len += inchr() ; tag = inchr() ; if ( tag==ERROR_TAG ) { addtrailerr(p ,0,ERROR_TAG) ; while) (ch=mchr()) '= EOF it navi_ιsspace(ch) ) ,- } else ch = ' ' ; /* Exit loop with non-EOF */ } if ( ch!=EOF ) addtrailerr(pg,HTM_ERR_TRAILCH,ERROR_TAG) ; f { nlevel!=0 ) addtrailer )pg,HTM_ERR_BADNEST,nestιng[nlevel-l] ) ; /* If we got an ISINDEX tag in the header then put a form at the end of */ /* the page (if we got one in the middle of the body we already inserted */ /* a form there) . */ if ( page->ιsmdex ) { if ( page->first==NULL ) lhtml.c Thu Mar 23 17:27:18 1995 39 page->fιrst = para = (Para *) myalloc(sizeof (Para) ) ,- else { for ( para = page->fιrst; para->pos ' =NULL; para = para->post ); para->post = (Para *) myalloc (sizeof (Para) ) ; para = para->post; } para->tagtext = page->ιιprompt; makeSearchForm(page,para) ,- } return(pg) ; } static int parse_null PROTOTYPE) (void *foo) ) { IErrorCbad parser state'"),- return EOF; ) HtmlPage * XVT_CALLC0NV1 FillHtmlPage(page, func, context) HtmlPage *page; t (*func) (voι d *) ; void "context; { if ( ipage) page = myalloc(sizeof (HtmlPage) ) if (page) { #ιf Dbg_Test char buffer [50]; static index, sprintf (buffer, "test%d.html" , ιndex++) ,- dump = fopentbuffer, "w" ) , •endif infunc = func,- mctx = context; nlevel = 0; foundplain = 0; slurpHtmlPage (page) ; infunc = parse_null; inctx = (void *)NULL, •if Dbg_Test fclose (dump) ,- •endif ) return page; } void XVT_CALLC0NV1 ParaListFree (first) Para *first; { Para *next; while ( first!=NULL ) { next = fιrst->post; if ( fιrst->fιrst'=NULL ) ParaListFree(fιrst->first) ,- myfree((char *) fιrst->text) ; yfreeUchar *) first->tagtext) ,- myfree((char *) first) ; first = next; } } void XVT_CALLCONVl KillHtmlPage(page) HtmlPage 'page; { myfree(page->url) ; myfree(page->docname) ; myfree(page->title) ; myfree(page->style) ; lhtml . c Thu Mar 23 17 : 27 : 18 1995 40 myfree (page->upl ) , myfree (page->uptιt ) , if ( page->otherlιnks ) { t i ; for ( ι=0; page->otherlιnks[I] '=NULL; ++ι ) myfree((char *) page->otherlιnks[l] ) , myfreeI (char *) page->otherlinks) , } yfree!page->base) , if ( page->headerinfo ) { int l, for ( ι=0; page->headerιnfo[ι] '=NULL, ++ι ) my ree( (char *) page->headerιnfo[i] ) , myfree((char *) page->headennfo) , } myfree(page->headererrs) , myfree(page->traιlerrs) , myfree(page->traιlargs) , ParaListFree(page->firs ) myfree(page) , } int HTML_AttrValue(mt tag, char *name) { struct attribs *attr, if ( key2names[tag]==NULL | | (attr = key2names[tag]->attr)== none ) return! false ) , while I attr->name'=NULL ) { if ( strcmp(attr->name.name)==0 ) return attr->value, ++attr, } return false, ) t _HTML__HasAttr(str,len,tag,output,osize,name) char *str, "output "name, t len, tag, osize, { struct attribs "attrs, attrs = parseAttrs(NULL,tag,str,len,0) f ( attrs==NULL ) return)false) , while ( attrs->name'=NULL ) { if ( strcmp(attrs->na e,name)==0 ) { if ( 'attrs->present ) return false, if ( output==NULL ) return true, if ( attrs->len==0 ) output[0]='NO' , else { len = attrs-> en, if ( len>osιze-l ) len = osιze-1; strncpyfoutpu ,attrs->val len), output[len]='NO' , ) return true, } ++attrs, ) return false. lhtml . c Thu Mar 23 17 : 27 : 18 1995 41 } int XVT_CALLC0NV1 HTMLJHasAttr(str,output,osize,name) char *str, *output, 'name; int osize; { int tag, len; if ( output!=NULL ) Output = 'NO' ; if ( str==NULL ) return false; len = ((unsigned char *) str) [HTML_LEN_HIGH] '256 + ((unsigned char ♦ ) str) [HTML_LEN_L0 W); tag = ((unsigned char *) str) [HTML_POS_TAG] ; return( _HTML_HasAttr(str+4, len,tag,output,osize,name) ) ; } int XVT_CALLCONVl HTML_HasAttrStr(str,tag,output,osize,name) char *str, 'output. *name; int tag, osize; { if ( outpu !=NULL ) ♦ output = 'NO' ; if ( str==NULL ) return false,- return) _HTML__HasAttr(str,strlen(str) ,tag,outpu ,osize,name) ) ; ) struct attribs * XVT_CALLC0NV1 HTML_GetAttrs(str) char *str; { int tag, len; len = ((unsigned char *) str) [HTML_LEN_HIGH] *256 + I (unsigned char *) str) [HTML_LEN_LO W]; tag = ((unsigned char *) str) [HTML_POS_TAG] ; return( parseAttrs(NULL,tag,str+4,len,0) ) ,- ) /* Skip to the HTML end tag for the current tag. */ char * XVT_CALLC0NV1 TagSkipToEndlpt) char *pt; { int htag, len; int tag; if ( *pt!=HTML_MARK ) return( pt ) ; tag = ((unsigned char *) pt) [HTML_POS_TAG] ; len = ((unsigned char *) pt) [HTML_LEN_HIGH]*256+( (unsigned char *) pt) [HTML_LEN_LOW] ,- pt += len+HTML_HEAD_LEN; while ( *pt ) { while ( *p !=HTML_MARK it *pt ) ++pt; if ( i'pt ) return( pt ) ; htag = ((unsigned char *) pt) [HTML_POS_TAG] ; len = ((unsigned char *) pt) [HTML_LEN_HIGH] '256+( (unsigned char *) pt) [HTML_LEN_LO W]; if ( htag==END_TAG ii ((unsigned char *) pt) [HTML_END_TAG]==tag ) return( pt + len+HTML_HEAD_LEN ) ; else if ( htag==tag ) /* Nested inside itself! */ pt = TagSkipToEndlpt); else pt += len + HTML_HEAD_LEN; lhtml.c Thu Mar 23 17:27:18 1995 42 } return( pt ) ; ) int XVT_CALLCONVl TagHasWidth(pt) char *pt; { int tag; char buffer[20] ; if ( *pt=='N0' ) return false; if ( *pt!=HTML_MARK ) return true; tag = ((unsigned char *) pt) [HTML_POS_TAG] ; if ( tag==SELECT_TAG | | tag==TEXTAREA_TAG | | tag==IMG_TAG | | tag==BR_TAG | | tag==HR_TAG ) return true; else if ( tag==INPUT_TAG ) { if ( !HTML_HasAttr(pt,buffer,sizeof(buffer) , "TYPE") | | strmatch(buffer, "hidden" ) !=0) return true; } return false; } int XVT_CALLCONVl TaglsField(pt) char *pt; { int tag; if ( *pt=='N0' ) return false; if ( *pt!=HTML_MARK ) return false; tag = I (unsigned char *) pt) [HTML_POS_TAG] ; if ( tag==INPUT_TAG | | tag==SELECT_TAG | | tag==TEXTAREA_TAG ) return true; return false; } int XVT_CALLC0NV1 TaglsPara(tag) int tag; { returnt tag>=PARA_START tt tag<PARA_END ); } int XVT_CALLCONVl TagLen(pt) char *pt; { int len; if ( *pt=='N0' ) return 0; if I *pt!=HTML_MARK ) return 1; len = ((unsigned char *) pt) [HTML_LEN_HIGH]"256+ ( (unsigned char *) pt) [HTML_LEN__LOW] , return( len+HTML_HEAD_LEN ) ; } int XVT_CALLC0NV1 Taglncr(pt) char *pt; { int len; int tag; char "end; if I *pt=='N0' ) return 0; if ( "pt!=HTML_MARK ) return 1; tag = ( (unsigned char *) pt) [HTML_P0S_TAG] ; lhtml.c Thu Mar 23 17:27:18 1995 43 len = ((unsigned char *) pt) [HTML_LEN_HIGH] "256+ ( (unsigned char *) pt) [HTML_LEN_LOW] . if ( tag ' =SELECT_TAG it tag '=TEXTAREA_TAG ) return! len+HTML_HEAD_LEN ), end = TagSkιpToEnd(pt) , returnIend-pt) , } char * XVT_CALLC0NV1 TagGetName<tag) int tag, { if I tag<0 ii tag>=-128 ) tag += 256, if I tag<0 | | tag>=sιzeof (key2names) /sizeof (key2names [0] ) | | key2names [tag) ==NULL ) return! NULL ) return I key2names [tag] ->name ), } mt XVT_CALLC0NV1 TagNeedsTermmator( ag) mt tag { if I tag<0 it tag>=-128 ) tag += 256 if I tag<0 | | tag>=sιzeof (key2names) /sizeof (key2nameε [0] ) | | key2names [tag] ==NULL ) return! false ) , return! key2names [tag] -.terminated ), } int XVT_CALLC0NV1 TagTextMatches (char *t, Para "para) ( unsigned char *tstr, *pstr, int len, tstr = (unsigned char *) t, pstr = (unsigned char *) (para->tagtext) len = 256*tstr[HTML_LEN_HIGH]+ tstr [HTML_LEN_LOW] , if ( para->tag'=tstr[HTML_POS_TAG) ) return! false ) , tstr += HTML_HEAD_LEN, while ( navι_ιsspace( *tstr) tt len>0 ) { --len ++tstr, } if ( len==0 ii pstr==NULL ) returnI true ) , while ( navι_ιsspace( *pstr) ) ++pstr, while ( len>0 it *ρstr ) { if I navι_ιsspace( *tstr) tt navι_ιsspace( "pstr) ) { while I navι_ιsspace( "tstr) tt len>0 ) { --len ++tstr } while ( navι_ιsspace("pstr) ) ++pstr } else if ( "tstr '= "pstr) return! false ) , else { --len, ++tstr ++pstr } } while ( navι_ιsspace( *tstr) tt len>0 ) { —len, ++tstr, } while ( navι_ιsspace( *pstr) ) ++pstr, return! len==0 ii *pstr=='N0' ) } char * XVT_CALLC0NV1 HTML__last (pt) char *pt, { while ( *pt'='N0' ) pt += Taglncr(pt), return(pt) , ) mt XVT_CALLC0NV1 HTML_len(start) char *start; { char *pt = start, if ( pt'=NULL ) lhtml.c Thu Mar 23 17:27:18 1995 44 while ( *pt'='N0' ) pt += Taglncr(pt); return(pt-start) ; } mt XVT_CALLC0NV1 HTML_tag(pt) char *pt; { return ((unsigned char *)p ) IHTML_POS_TAG] ; } /* No html elements in the text */ int XVT_CALLCONVl HTML_pla (star ) char *start; { return( strchr(start,HTML_MARK)==NULL ) ; ) /* Does every HTML item within the string that needs one have a matching end' */ int XVT_CALLC0NV1 HTML_matched(pt,len) char *pt; t len,- { int tag; nlevel = 0,- while ( —len>=0 ) { if ( *pt'=HTML_MARK ) ++pt, else { tag = ((unsigned char *) pt) [HTML_POS_TAG] ; if ( tag==END_TAG tt nlevel==0 ) return! false ) ; /* END with nothing to match it */ else if ( tag==END_TAG ) --nlevel; else if ( TagNeedsTermmator(tag) ) newnest(tag! ■ len = ( (unsigned char *) pt) [HTML_LEN_HIGH] "256+( (unsigned char *) pt) [HTML_LE N_L0W] ; pt += len+HTML_HEAD__LEN; } } return! nlevel==0 ) ,- } struct chartab *XVT_CALLC0NV1 HTML_charnames PROTOTYPEI (void) ) { return(charnames) , ) void XVT_CALLC0NV1 HTML_FιllTag(char *buf, int tag) { buf[0] = HTML_MARK; buf[HTML_LEN_HIGH] = 0; buf[HTML_LEN_LOW] = 0, buf[HTML_POS_TAG] = tag, buf[HTML_HEAD_LEN] = 'NO'; } void XVT_CALLC0NV1 HTML_FιllEndTag(char *buf, int tag) { buf[0] = HTML_MARK; buf[HTML_LEN_HIGH] = 0; buf[HTML_LEN_LOW] = 1; buf[HTML_POS_TAG] = END_TAG; buf[HTML_END_TAG] = tag; buf[HTML_END_LEN] = 'NO'; } /"** more parse functions ****/ /* ** parse_stπng - feed one character at a time from string *ppc */ lhtml.c Thu Mar 23 17:27:18 1995 45 t parse_stπng(char **ppc) { mt i; /* charcter to return (NB: must be t to hold EOF) */ assert (ppc '= NULL); assert Cppc '= NULL) ; 1 = **ppc; if (l != 'NO') { ++*ppc; } else { = EOF; ) return l,- int parse__file(fp) FILE *fp; { return getc(fp); mt text2html (tb) textblob *tb; swιtch(tb->state) { case tb->state++; return '<' case tb->state++; return 'P' case tb->state++; return 'R' case tb->state++; return 'E' case tb->state++; return ' > ' case int c = getc(tb->fp) ; switch(c) { case ' Sc ' tb->state = 10; return 't ' ; case '<' tb->state = 20; return 'i ' ; case EOF tb->state = 30; return '<' , } return c } tb->state++; tb->state++; tb->state++; tb->state=5; tb->state++; tb->state++; tb->state++; tb->state=5; tb->state++; tb->state++; tb->state++; tb->state++; tb->state++; return EOF; default: IError ( "text2html messed up"); tb->state = 0; return EOF; } /* Walk through a paragraph keeping track of the nesting within it */ void XVT_CALLCONVl _FmdNestmg(Para "para, int offset, Nestinfo *nι) { unsigned char *pt = (unsigned char ") (para->text) ; unsigned char 'end = pt+offset; if ( pt'=NULL ) while ( "pt it pt<end ) { lhtml. c Thu Mar 23 17 : 27 : 18 1995 46 if ( "pt==HTML_MARK ) { if I pt[HTML_POS_TAG]==END_TAG ) { if I pt[HTML_END_TAG]>=PARA_START tt pt[HTML_END_TAG]<=PARA_END ) /* Ignore it */,- else if I nι->ncnt>0 ) --nι->ncnt; else IErrorl"Nesting screwed up n FindNesting"), } else f ( TagNeedsTermmator(pt[HTML_P0S_TAG] ) ) { if ( nι->ncnt>=nι->nmax ) { nι->nestιng = (unsigned char *) myreallocI (char *) ni-.-nesting, nι->nm ax+=10 ) ; nι->tagtext = (unsigned char **) myrealloc I (char *) nι->tagtext, nι->n max*sizeof(unsigned char **) ) ; _ } ni->nestιng[nι->ncnt] = pt[3]; nι->tagtex [nι->ncnt++] = pt; ) pt += HTML_HEAD_LEN+256*pt[HTML_LEN_HIGH]+pt[HTML_LEN_LOW] ; ) else ++pt; } } void XVT_CALLCONVl FindNesting ( Para *para , int of fset , Nestinfo 'ni l { nι->ncnt = nι->nmax = 0 ; nι->nestmg = NULL ; nι->tagtext = NULL; _FιndNestmg(para, offset, ni); } mt XVT_CALLC0NV1 TagActivelPara "para, int offset, int tag) { Nestinfo ni; int l, ret; FindNesting(para,offset,tni) ,- ret = 0; for ( ι=0; i<ni.ncnt; ++ι ) if I ni.nesting[i]==tag ) ret = 1,- myfreeI n .nesting ); myfree! m.tagtext ); return ret, } mt CHtmlErrorOutput) (char *) = 0; mt _html_error(char *fmt, ...) { if(HtmlErrorOutput) ( static char buf [0x1000]; va_lιst ap; va_start(ap, f t) ; vsprintf(buf, fmt, ap) ; va_end(ap) ; return HtmlErrorOutpu (buf) ; ) return 0; } local.cxx Thu Mar 23 13:10:05 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved •include <stdlιb.h> •include "crud.h" •include "str.h" •include "guess.h" •include "response.h" •include "xlocal.h" •include "weblet.h" •include "lfunc.h" extern "C" { extern char dιr_char, •include <strιng.h> } •if defined(macintosh) # define BINREAD "rb' # define BINWRITE "wb" #else # define BINREAD "r" # define BINWRITE "w" •endif int localsavefchar *, char *, mt , int) , int localload(char *, char *, Form *, int), int localkill (char *, char *) ; int localbrowsefchar *, char *) , int localcrud(Crud "crud) { char "url = (crud->url ' crud->url • crud-> orm->URL) , switch (crud->type) { case C: return localsave(url, url, crud->sιd, 1) , case R: return localload(url, url, crud->form, crud->mfo) , case U: return localsaveturl , url, crud->sιd, 0), case D return localkill (url , url) , case B: return localbrowsefurl , url); default: return fivehundredf "unknown crud type in localcrud"),- } static mt htmldnt status, char "a, char *b, char *c) { wstrand ws, ws .create(status, "text/html") , heading (tws, a) ; ws .print (b, c) ; closing(tws) ,- return ws .close( ) ; } static t DocFromWad(char "dir, char "base, rstrand "rs) { mt n; char "name = (char * ) 0 , long size; local.cxx Thu Mar 23 13:10:05 1995 2 char "type = (char *)0; cnar buffer[0x100] ; while! (n = rs->getlιne(buffer, sizeof(buffe )) ) '= EOF) { f(m=pmatchI"Content-Name- ", buffer)) name = copyIm) ; else f(m=pmatch("Content-Type ", buffer)) type = copy(m) , else f(m=pmatc ("Content-Length ", buffer)) size = atol(m) ; } else { FILE *fp, int len; fsys_buιld_name(di , name, buffer, sizeof (buffe )) , fp = fopen(buffer, BINWRITE); whιle(sιze) { len = (sizeof (buffer) > size ' size sizeo (buf er) ) , len = rs->read(buffer, len), if(fp) fwrite(buffer, 1, len, fp) , ) if(fp) fclose(fp) ; myfree(naune) , myfree(type) ; } } return html (206, "Success", "%s modified", base), } int localsave(char *dest, char "base, int rid, mt create) { rstrand rs; if(pmatchI "application/x-naviwad" ,rs. ypeI) ) ) { ifI sys_exιsts(dest) tt ' fsys_ιsdoc(dest) ) return html(403, "Create Failed' , "%s already exists' , base), ifI !fsys_exιsts(dest) ) fsys_mkdιr(dest) , if( !fsys_exιsts(dest) ) return html(403, "Create Failed", "can't create %s", base); return DocFromWadides , base, trs) ; } else { if(create) { if( ' sys_exιsts(dest) ) { return html(403, "Create Failed", "%s already exists", base) } } FILE "fp = fopen(dest, BINWRITE); ιf(fp) { rs.fιle(fp) ; fcloseIfp) ; sys_setfilecreator(dest, (char *) rs.type(J), if (create) return html(201, "Success", "%s created", base), else return html (206, "Success", "%s modified", base), ) else { return html(403, "Update Failed", "couldn't write %s" , base); } ) local.cxx Thu Mar 23 13:10:05 1995 3 ) extern "C" { int listing(struct cstr "cws, char "name) { wstrand "pws = (wstrand "Jews, if(name[0] '= ' ') pws->pnnt( "<A HREF=\"%sN">%s</A><BR>Nn", name, name), return 0, } int browse(struct cstr "cws, char "name) { wstrand "pws = (wstrand "lews, char "type, type = (fsys_ιsdιr(name) ' (fsys_ιsdoc(naune) ' "application/x-navidoc" • "application/x-navidir") • guess_suffix(name) ) ; •if defined(macintosh) if ( strcmp(type, "*/*" )==0 ) if (( type = fsys_mιme_from_type(url) )==NULL ) type = "*/*", •endif pws->prιnt("%s %sNn" ,type,naune) , return 0; } int browse_desktop(struct cstr *cws, char "name) { wstrand "pws = (wstrand *)cws; pws->prιnt("application/x-navidir %sNn",name) , return 0; ) int cfsys_ιterate_lιstιng(char "dir, void "assets) { return fsys_ιterate(dir (int (*) (struct cstr *, char "Jllistmg, assets), } int cfsys_ιterate_browse(char *dιr, struct cstr *pws) { return fsys_ιterate(dιr, (int (*) (struct cstr *, char *))browse, pws) ; } } static void normalize(int *low, int *hιgh) { ifClow - 'high) { extern "C" { void URLTrans(char *, char *, char *, char *, char *, int, t) , int _crud_error(char *fmt, ... ) ; } static int CheckMapping(char "base, mt sid, int x int y) local.cxx Thu Mar 23 13:10:05 1995 4 { struct cstr "rs = RsOpenId(sιd,0) , char buf[0x100] ; char spam[0x100] ; char *m, strcpy(spam, ""), while(RsGetLine(rs, buf, sizeof(buf)) '= -1) ( if(m=pmatch("rect ", buf)) { mt left, top, right, bottom; char *p = strchr(m, ' '), *p++ = 'NO' ; sscanf(p, "%d,%d %d,%d" ,tleft,t op.trιght,tbo torn) , normalize(tlef , iright) , normalize(itop, tbottom) , ιf(x >= left tt x < right it y >= top tt y < bottom) { strcpylspam, m) , break; } } else if(m=pmatch("default ", buf)) { strcpylspam, m) , } ) i ("spam) { char abuf[0x40] , URLTrans(spam, NULL, base, buf, abuf, sizeof(buf), sizeof(abuf)) , lfCabuf) { strcat(buf, "#"), strcatlbuf, abuf) ; ) _mfo("%s:%s -> %sNn" , spawn, base, buf) return redirec (buf) , } return noop() , ) extern "C" int fsys_alιas(char *, char *, int), int localloadlchar "dest, char "base. Form "form, int info) { •if definedITHINK_C) t cfsys_ιterate_lιstmg(char *, void *), i (form tt 'pmatch("applicat on/x-navimap" , guess_suffix(dest) )) { return html{501, "No local form submission or searching", "can't submit forms or search locally (yet 1 )",""), } else { char *doc; if (doc = fsys_ιsdoc(dest) ) { dest = doc; } else if(fsys_ιsdιr(dest) ) { wstrand ws; ws.create(200, "text/html"), ws.prmt("<HEAD><TITLE>Nn") , ws .print ("directory listing of '%s'",base), ws. print ( "</TITLExBASE HREF=N "%s/lιstmgN ' > " .base) , ws. print ( "</HEADxBODY>Nn" ) ; ws. print I "<Hl>lιstmg of %s -</HlxHR>" .base) , ws. print ( "Listing for <A HREF=V N ">parent</AxBR>Nn" ) , cf sys_ιterate_lιstιng(dest, tws) , ws. print ( "<HRx/BODY>Nn" ) , return ws . close ( ) , } { local.cxx Thu Mar 23 13:10:05 1995 5 FILE "fp = fopen(dest, BINREAD), struct strandinfo si, wstrand ws; ιf(!fp) { if(fsys__exιsts (dest) ) { return html (403, "Retrieve Failed", "couldn't read %s" , base), ) else { char buffer[0x100] ,- if(fsys_alιas(dest, buffer, sizeof(buffer) ) ) return redirect(buffer) , si.status = 404; si.type = "text/html", si.lastmod = 0, si.expires = 0; si.modifyable = fsys_modιfyabledιr(dest) , si.document = copy(fsys_docfor(dest,base) 1 , ws.createϋsi.mem) , headingltws, "Retrieve Failed"), ws.print("couldn't find %s", base), closing(tws) , } } else ( si.status = 200; si.type = guess_suffιx(dest) ; •if defined(macintosh) if ( strcmplsi.type, "*/*')==0 ) if (( si. ype = fsys_mιme_from_typ (dest) 1==NULL 1 •endif si.size = fsys_sιze(dest) ; si.date = tιme(0); si.lastmod = fsys_lastmod(dest) , si.expires = 0, si.modifyable = fsys_modιfyable(dest) , si.document = copy!fsys_docfor(dest,base) ) , _mfo( "content-type: %s (%s)Nn", si.type, dest), ws.create(tεi, disk); ιf(ιnfo) { fclose(fp) , return ws.info() ,- } ws.fιle(fp) ; fclose(fp) ,- ) if(form tt pmatch!"application/x-navimap" , si.type)) int x, y; if(form->NumFιelds == 1 it sscanf(form->f elds[0] .value, "%d,%d" ,tx,ty) == 2) return CheckMappin fbase, ws.closet), x, y) , ws.forge () , return flvehundred("bad mapping args"), ) return ws.close() ; } int localkill(char 'dest, char 'base) { if( (fsys_ιsdoc(dest) it syε_rmdoc(dest) == 0) | local.cxx Thu Mar 23 13:10:05 1995 6 ( 'fsys_ιsdιr(dest) it fsys_delete(dest) == 0)) return html(205, "Success", "%s deleted", base), return html(403, "Failure' , "couldn't delete %s' , base); } mt localbrowselchar 'dest, char 'base) { if ( 'strcmp(dest, "NtDesktop") ) { wstrand ws; ws.create{200, "application/x-navibrowse"1 ; fsys_browse_desktop( (struct cstr *)tws), return ws.close)); } else if(fsys_ιsdιr(dest) ) { wstrand ws; ws.create(200, "application/x-navibrowse") , cfsys_ιterate_browse(dest, (struct cstr *)tws), return ws.closet); ) return html(403, "Browse Failed", "couldn't browse %s", base), ) extern "C" { int clocalcrud(Crud "connection, char "pageroot, char "servroot) { char dest[0x100]; char basetOxlOO] ; char "url = (connectιon->url ' connectιon->url connectιon->form->URL) , mt ret, if (( (strlen(pageroot) + 1 + strlen(url) + 1) > sizeof (dest)) | | ( (strlen(servroot) + 1 + strlen(url) + 1) > sizeof (base))) { return fivehundredt"Pathname too longNn" ) ; } sprintf(dest, "%s%s" ,pageroot,url) ; spnπtf(base, "%s%s" ,servroot,url) ; if) 'strcmp(connectιon->method, "GET") | ] 1 strcmp(connectιon->method, "POST") j | 'strcmp(connectιon->method, "HEAD" ) ) ( return localloadfdest, base, connectιon->form, connectιon->mfo) , } else if('strcmp(connection->method, "BROWSE") ) { return localbrowsetdest, base); } else if('strcmp(connectιon->method, "DELETE"1 ) { return localkill(dest, base), } else /* not quite true, of course */ { return localsave(dest, base, connectιon->sιd, connectιon->type == C) } response.cxx Tua Jan 31 12:35:19 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •include "str.h" •include "response.h" void heading(wstrand "pws, char *str) { pws->wrιte("<HEADxTITLE>" ) ; pws->wπte(str) ; pws->wrιte ( " < /TITLEx/HEAD><BODYxHl> " ) , pws->wrιte ( str) ; pws->wrιte ( " </Hl> " ) ; } void closing(wstrand *pws) { pws->wπte("</B0DY>") ; } extern "C" { int flvehundredtchar *str) { wstrand ws; ws.create(500, "text/html" 1 , heading(tws, str) ; closing(tws) ; return ws.closet); } mt twohundred(char "fmt, .. ) { wstra_nd ws; va_lιst ap; static char buf[0x100]; va_start(ap, fmt) ; vspnntf(buf, fmt, ap) ; va_end(ap) ; ws.create(200, "text/html" ) , heading(tws,buf) ; closing(tws) ; return ws.closet); } mt redirect(char *loc) { wstrand ws; ws.create(302,loc) ; return ws.close!); ) mt noop() { wstrand ws; ws.create(204, "") ; return ws.closeI ) ; } } ■tr.cxx Thu Mar 23 13:04:18 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. •include <stdarg.h> •include <strιng.h> •include <ctype.h> •include "str.h" extern "C" { •include "guess.h" •include "Ifunc.h" mt unlinktconst char *); extern char "mytmpnaunIchar *); /* xlocal.c */ ) •if defined(macintosh) # define BINREAD "rb" # define BINWRITE "wb" #else # define BINREAD "r" # define BINWRITE "w" •endif strand: :strand(strandinfo "si, loc _from) { serial = nextserno++; status = sι->status; type = sι->type ? copy(sι->type) : copy!"*/*"), lastmod = sι->lastmod; expires = sι->expιres; modifyable = sι->modιfyable; naviserver = sι->navιserve ; document = copy(sι->document) ,- from = _from; refcnt = 0; dirty = 0; storage = (char *)0; current = mem; filename = (char *) 0,- url = (char *)0, cacheurl = (char *)0, cachebrand = (void *)0, list = (strand **)0; next = (strand *)0; } strand: :-strand() { remlist() ; myfree(type) ; myfree(document) , delete storage; storage = 0; if(filename) unlink ( fileneune) ; myfree(filename) ; myfree(url) , myfree(cacheurl) ; int strand: :nextserno atr.cxx Thu Mar 23 13:04:18 1995 2 strand "strand: :sids = (strand *)0; strand "strand: :caches = (strand *)0; void strand: :remlist() { if(list) { ifClist == this) *list = this->next; else { strand "last = 'list; while(last->next != this) last = last->next; last->next = this->next; } this->next = (strand *)0; list = (strand **)0; } } void strand: :addlist(strand **_list) { list = _list; next = *list; *list = this; } int strand: :gensid() { iftilist) { addlist(tεids) ; } return serial; } void strand: :expire() { _infoI "expire: %sNn" , cacheurl); re list() ; if! irefcnt) delete this; else addlist(tsids) ; ) void strand: :reaperI ) { strand *s, 'next; forts = caches; s != (strand *)0; s = next) { next = s->next; if(s->dirty tt s->expirea I) < time(0) ) s->expire( 1 ; } } strand *■ strand: :find(int sid) { if! isid) return (strand *)0; str.cxx Thu Mar 23 13:04:18 1995 strand *s; for(s = sids; s '= (strand *)0; s = s->next) { ιf(s->serial == sid) return s,- ) forIs = caches; s '= (strand *)0; s = s->next) { ιf(s->serιal == sid) return s; } return s; } strand. :cache(int sid, char *url, void *brand) { ιf(sιd > 0 tt url) { strand *s; if(Is = f d(sιd)) it s->status == 200) { _mfo("cache {%d %s %x)Nn", sid, url, brand), s->remlιst() , s->addlιst(teaches) ; i (s->cacheurl) delete s->cacheurl, s->cacheurl = copy(url); s->cachebrand = brand; } } return sid; ) int strand: :flush(char *url) { mt n = 0, strand *s; ιf(url == (char *)0) { // flush entire cache strand *s, "next; for(s = caches; s '= (strand *)0; s = next) { next = ε->next; s->expιre() ; n++; } return n; } whιle(s = cached(url,0) ) { s->expιre( ) ; n++; } return n; ) int strand: :checkfor(char *url, void 'brand, t onlyinfo) { strand *s; if(url ti (s = cachedturl, brand))) { if(s->current '= info || onlyinfo) { return s->gensιd() ; } } return 0; str.cxx Thu Mar 23 13:04:18 1995 4 } strand * strand: :cached(char *url, void 'brand) { strand *s; for(s = caches; s != (strand *)0; s = s->next) if(strcmp(url, s->cacheurl)==0) if(!brand || brand == s->cachebrand) brea ; return s; } void strand: :addref() { refcnt++; } void strand: :delref() { dirty = 1; if(--refcnt == 0 it list != teaches) delete this; } iostrand: :iostrand() { valid = 0; s = (strand *)0; fp = (FILE *)0; } iostrand: :-iostrand() { closed) ,- } void iostrand: :open(strand *__s) { closed) ; if(s = _s) { s->addref() ; valid = 1,- iorewind{) ; } } void iostrand: :iorewind)) { cur = 0; if(s->current == disk) { if(fp) fclose(fp) ; fp = fopen(s->filename, BINREAD); } } void str.cxx Thu Mar 23 13:04:18 1995 iostrand: :close(int del) { if (valid) { if(s->current == disk tt fp) fclose(fp) ; if(del) s->delref() ; s = (strand *)0; valid = 0; } } /""""/ rstrand: :rstrand() { url = (char » )0; } rstrand: :-rstrandI ) { ) int rstrand: :open(char *url) { iostrand: :open(strand: :cached(url,0) ) ; return valid; ) int rstrand: :open(int sid) { iostrand: :open(strand: :fin (sid) ) ; return valid; } long rstrand: :available() { return(s->size - cur); } int rstrand: :read() { if(!valid || cur >= s->size) return EOF; if (s->current == mem) return (unsigned char)s->storage[cur++] else { unsigned char c; ifdfp) { fp = fopen(s->filename, BINREAD) ; fseektfp, cur, 0) ,- } cur++; if(fread(tc, 1, 1, fp) ) return c; else return EOF; } int rstrand: :read(char *buf, int len) { str. cxx Thu Mar 23 13 : 04 : 18 1995 6 if( 'valid) return EOF; mt l, c; ford = 0; l < len it (c = readO) '= EOF; buf[ι++] = c) , return l, } int rstrand: :getlme(char "buf, t len) { ifI 'valid) return EOF, int c, l; ford = 0; l < len, ι++) { c = read( ) , if(c == EOF I I c == 'Nn' ) { ιfd) { whiled >= 0 tt isspacelbuf[--ι] )) , ι++ ,- } buf[ι] = 'NO'.- return (ι==0 it c==E0F) ' EOF l, } buf[ι] = c, } while(c '= EOF it c '= 'Nn') ( c = read( ) ; ι++; } return d == 0 ti c == EOF ' EOF l) , } t rstrand: : file (FILE "out) { int tot = 0, if (s->current == mem) fwrite(s->storage + cur, 1, tot = s->sιze - cur, out) else { static char bu [0x100], int len, whileϋen = freadtbuf, 1, sizeof (buf), fp) 1 { fwπtelbuf, 1, len, out), tot += len; } ) return tot, } char * rstrand: :toflie() { if (s->current == mem) { char tempbuf [0x100] ,- s->current = disk, s->fιlena_me = copy(mytmpnam(tempbuf)) , fp = fopen(s->fιlena_me, BINWRITE) ; fwrite (s->storage, 1, s->sιze, fp) , fclose(fp) ; delete s->storage; s->storage = 0; fp = fopen (s->f ilenaune , BINREAD) , fseek l fp , cur , 0 ) , str. cxx Thu Mar 23 13 : 04: 18 1995 7 ) return s->fιlename; } void * rstrand: :contextI) { return s->ctx; } void rstrand: :close(void *ctx) ( s->ctx = ctx, lostrand: :closed) ; } /*""""*/ wstrand: ■ -wstrand() { forget{) , } mt wstrand: :createIint status, const char *type) { struct strandinfo si, si.status = status,- sl.type = type; si.lastmod = si.expires = 0; si.modifyable = 0, si.naviserver = 0, s . ocument = {char *)0; forget() ; s = new strand(tsι, mem) ; cur = 0, overflow(O) ; return valid = 1, } mt wstrand: :create(strandinfo *sι, loc from) { forget() ; s = new strand(s , from) ; cur = 0; overflow(sι->sιze) ; return valid = 1; } void wstrand: :overflow(long _max) { max = _max; ιf(max < 0x8000) { s->current = mem, if ( max<=0 ) max=l, /* realloc gets very confused if it */ /* has to reallocate something which was allocated */ /* with size 0 */ /* malloc is not guaranteed to */ /* allocate something of size 0 anyway */ s->storage = (char *)myrealloc(s->storage, max), str.cxx Thu Mar 23 13:04:18 1995 8 } else if(s->current '= disk) { char tempbuf[0x100] ; s->current = disk; s->filene_me = copy(mytmpnamttempbuf) ; fp = fopen(s->filename, BINWRITE); fwrite(s->storage, 1, cur, fp) ; delete s->storage; ε->εtorage = 0; } ) int wstrand: :write(char c) { ifI!valid) return -1; if(cur == max) overflow(max < 0x200 ' 0x200 : 2 *max) , if(s->current == mem) ( s->storage[cur++] = c; } else { cur += fwrιte(tc, 1, 1, fp) ; ) return c; } int wstrand: :write(char *str) ( if( !valid) return -1; char "start = str; whιle(*str) writeCstr++) ; return(str - start) ) int wstrand: :write(char "buf, int len) { if(!valid) return -1; for(mt i = 0; i < len; ι++) write(buf[i] ) ; return len; } int wstrand: :print(char *fmt,...) { if( !valid) return -1; mt ret; va_lιst ap; va_start(ap, fmt) ; ret = vprmtlfmt, ap) ; va_end(ap) ; return ret; str. cxx Thu Mar 23 13 :04 : 18 1995 static char wrbuf [0x1000] ; mt wstrand: :vpr int (char " fmt , va_lιst ap) { if ( ' valid) return - 1 ,- vsprmtf(wrbuf, fmt, ap) ; int len = strlen(wrbuf) ; writetwrbuf, len); return len; } int wstrand: :file(FILE *fp) { mt len, tot = 0; whileden = freadlwrbuf, 1, sizeof(wrbuf) , fp) ) { wrιte(wrbuf, len); tot += len; ) return tot,- } int wstrand: :info() { if (s->current == mem) { myfree(s->storage) ; s->storage = 0; ) else { unlink(s->filename) ; ) s->current = ::ιnfo; return s->gensιd(); } int wstrand: :snapshotI) { s->sιze = cur; if(s->current == disk) fflush(fp) ,- return s->gensιd() ; ) int wstrand: :close() { int sid = snapshot!); if(strcmp(s->type, "*/*") == 0) { delete s->type; if(s->current == mem) { s->type = copy(guess_buf(s->storage, s->sιze) ) , } else { static char buf[0x100],- iorewind() ,- t len = freadtbuf, 1, sizeof(buf), fp) ; s->type = copy(guess_buf(buf, len)); } } lostrand: :close(0) ; return sid; atr.cxx Thu Mar 23 13:04:18 1995 10 void wstrand: :forge () { iostrand: :closed) ; valid = 0; } extern "C" { int CacheFlush(char *name) { return strand: :flush(name) ; } void CacheReap() { strand: :reaper() ; } int CacheCheckFor(char *url, void *brand, int onlyinfo) { return strand: :checkfor(url,brand,onlyinfo) ; } int ValidInCache(char *url) { strand *s; int sid; if (( sid = strand: :checkfor(url, ULL, rue) )==0 ) return 0; if It s = strand: :find(sid) )==NULL ) return 0; return! s->expireatI) >= time(O)),- } struct cstr *RsOpenCache(char *name, struct strandinfo *si) { rstrand *rs = new rstrand; if(rs->open(name) ) ( if(si) { si->status = rs->status() ; si->type = rs->type(); si->size = rs->size(); si->lastmod = rs->lastmod() ; si->expires = rs->expires() ; si->modifyable = rs->modifyable() ; si->naviserver = rs->naviserver{) ; si->document = rs->document() ; ) return( (struct cstr *)rs); } delete rs; return (struct cstr *)0; } struct cstr *RsOpenId(int sid, struct strandinfo *si) { rstrand *rs = new rstrand; if (rs->open(sid) ) { if(si) { si->status = rs->status () ; ■tr.cxx Thu Mar 23 13:04:18 1995 11 sι->type = rs->type(); sι->sιze = rs->sιze(); sι->lastmod = rs->lastmod() ; sι->expιres = rs->expιres() ; sι->modιfyable = rs->modιfyable() ,- sι->navιserver = rs->navιserver() ,- sι->document = rs->document() ; } return( (struct cstr *)rs); } delete rs; return (struct cstr *)0, ) nt Rsld(struct cstr *rιd) { if ( 'rid) return 0; return ((rstrand *)rid)->serιal() ,- } mt RsReadC(struct cstr-*rιd) { if(rid) return ((rstrand *)rid)->read() ,- else return EOF; ) int RsReadBuf(struct cstr "rid, char "buf, t len) { if(rid) return( (rstrand ")rid)->read(bu , len), else return 0, } int RsGetLine(struct cstr "rid, char "buf, t len) { i (rid) return! (rstrand *)r d)->getlme(buf, len); else return 0; } void RsRewind)struct cstr "rid) { if(rid) ((rstrand *)rιd)->ιorewmd() ; ) int RsFιllFιle(struct cstr "rid, FILE *fp) { if(rid) return! (rstrand *)rιd)->flie(fp) ,- else return 0 } char 'RsForceFile(struct cstr *rιd) { if(rid) return! (rstrand *)rιd)->toflie() , else str. cxx Thu Mar 23 13 :04:18 1995 12 return (char * ) 0 ; ) void 'RsContext(struct cstr *rid) { return (rid ? ((rstrand *)rid)->context{) (void *)0) } void RsCloseWCtxlstruct cstr "rid, void *ctx) { if(rid) { ((rstrand *)rid)->close(ctx) ,- delete ((rstrand *)rid); } } void RsClose(struct cstr "rid) { if(rid) { ((rstrand ")rid)->close(0) ; delete ((rstrand *)rid); } struct cstr "WsCreate(int status, const char 'type) { wstrand *ws = new wstrand; if(ws->creat (status, type)) return( (struct cstr *)ws); delete ws; return (struct cstr *)0; } struct cstr *WsCreateInfo(struct strandinfo *psi) { wstrand *ws = new wstrand,- if(ws->create(psi, web)) return( (struct cstr *>ws); delete ws; return (struct cstr *)0; ) int WsPutC(struct cstr *wid, int c) { if(wid) return ((wstrand *)wid)->write(c) ; else return 0; } int WsPutStr(struct cstr *wid, char *str) { if(wid) return ((wstrand *)wid)->write(str) ; else return 0; ) int WsPutBuf(struct cstr *wid, char *buf, int len) { if(wid) return ((wstrand *)wid)->write(buf,len) ; else return 0; str. cxx Thu Mar 23 13:04:18 1995 13 ) int WsPrmt (struct cstr *wιd, char *fmt, ) { if (wid) { va_lιst ap, va__start (ap, fmt), mt ret = ((wstrand * )wιd) ->vprmt (fmt , ap) va_end ( ap ) ; return ret, ) else return 0 ; } mt WsPutFile(struct cstr *wιd, FILE 'fp) { if(wid) return ((wstrand *1wid)->flie(fp) , else return 0; } int WsCloselstruct cstr *wιd) sid = ((wstrand *)wιd) ->close() , delete ((wstrand *)wιd), } return sid, } void WsForget(struct cstr *wιd) { if(wid) { ((wstrand *)wιd) ->forget ( ) , delete ((wstrand *)wιd), ) int CCrudDebugOutput) (char *) = 0, t _mfo(char *fmt, .. ) { if(CrudDebugOutput) { static char buf[0x1000], va_lιst ap, va_start(ap, fmt), vsprintf(buf, fmt, ap) , va_end(ap) , return CrudDebugOutpu (buf) , ) return 0, } int CCrudErrorOutput) (char *) = 0; int _crud_error(char *fmt, ...) { if(CrudErrorOutput) { static char buf [0x1000] ; va_lιst ap; va_start(ap, fmt), vsprintf (buf, fmt, ap) , str. cxx Thu Mar 23 13:04:18 1995 14 va_end(ap) ,- return CrudErrorOutpu (buf) ; } return 0; } } ab.cxx Mon Mar 20 12:13:00 1995 1 /" Copyright 1994-1995 NaviSoft. Inc. All rights reserved. */ •include <stπng.h> •include <stdlιb.h> •include "crud.h" •include "str.h" •include "guess.h" •include "response.h" •include "lfunc.h" int http(Crud *,char *, char*); int ftp(Crud *,char *); extern "C" { char "copy(const char *); void sleepdnt), int unlink(const char *); tιme_t timegmtstruct tm *); long millisec(void) ; char "proxyhost = NULL; } int webloadlCrud *) ; t webcrud(Crud "crud) { char *m; ιf(crud->url tt (m=pmatchI"ftp: //" ,crud->url1 ) ) return ftptcrud, ml ; switch(crud->type) { case C: case U: strand: :flush(crud->url) ; ifI 'crud->form) { return httptcrud, "PUT", crud->url) , } else { return httptcrud, "PUT", BuildFormStr(crud->form,NULL, 0) ) ,- } case D: strand: : flush(crud->url) , return httptcrud, "DELETE", crud->url), case R: if(sid = strand: :checkfor(crud->url,crud->auth,crud->ιnfo) ) { if(crud->reload) { rstrand rs; rs.openIsid) ; crud->smce = rs.dated; return webload(crud) ; } return sid; } return webloadtcrud) ; } case B: return httptcrud, "BROWSE", crud->url); case' X: break; } return fivehundredt"unknown crud type in [webcrud]"); wab.cxx Mon Mar 20 12:13:00 1995 mt webloadlCrud *crud) { char "url = crud->url; Form "form = crud->form; char "poststr = (char *)0; if(form) { if( ! form->method) url = BuildFormStrtform, NULL, 0), else { url = form->URL, poststr = BuildFormStrtform, NULL, 0), } ) ιf(poststr) { wstrand ws; ws.create(200, "application/x-www-form-urlencoded") ; ws.write(poststr) ,- crud->sιd = ws.close(); crud->smce = 0 ; crud->mfo = 0 ; } return http(crud, poststr ' "POST" (crud->ιnfo ' "HEAD' "GET"), url) } •include "task.h" class tcp : public task { long addr; char "status; mt sock; char ibuf[0x1000] ; mt pos, len; long tO; long traffic, tare; mt mitdnt, char *), int rlineichar *, int); public: unsigned t reading : 1, unsigned mt cooked . 1; unsigned mt verbose 1; mt min; tcp(task *, long, int, char *); tc (task *, char *, int, char *); -tcp() , mt statistics(char "buf, long whole); void resetstat() ; mt connected() ; int write(char *); int write(char *, int); int operator() () ; int hasdata() ; ab.cxx Mon Mar 20 12:13:00 1995 3 mt select I ) , partial ( ) , }, int tcp. statistics (char *buf, long whole) { long delta, bps, long amt = traffic - tare, delta = millisec () -tO, bps = (delta ' (traffιc'1000) /delta 0) , if ( 'whole) { if ( 'bps) spπntf{buf, "read %ld' , amt), else sprιntf(buf, "read %ld (%ld bps)' , amt, bps) , } else { if ( 'bps) sprintf (buf "read %ld%% of %ld" , amt*100/whole, whole) , else spπntf(buf "read %ld%% of %ld (%ld bps) %ld sees remaining' amt*100/whole whole, bps, (whole - amt) /bps) , } return (amt > whole) , } tcp: .resetstat ( ) { tare = traffic, } extern "C" { extern char "httpFromll ; } class ftptask public task { Crud "crud, tcp "ctl, "data, char "host, char "path, int param, t type,- char buf [0x1000] ; char err [0x1000] ; wstrand ws, long tot, t wasdir; void getpasvl), public . ftptas (Crud *, char *, char *); -ftptask() , partial ( ) , }. int ftp(Crud "crud, char *url) { char *p = strchrturl, '/'), char "host = (p ? copyn(url,p-url ) copy(url)), crud->comm = new ftptask(crud, host, (p'copy(p) :copy("/"))) , wab.cxx Mon Mar 20 12:13:00 1995 4 return 0,- } ftptask: :ftptasktCrud *_crud, char *_host, char *_path) : task(O) ( crud = _crud; host = _host; ctl = new tcp(this, host, 21, crud->status) ,- ctl->verbose = 1; path = _path; para = 0; type = 0; wasdir = 0; f ptask: :-ftptask! ) { delete ctl; myfree(path) ; myfree(hoεt) ; ) void ftptask: :getpasv{) { char pasvhost[0x20] ; int pasvport; int rep, hO, hi, h2, h3, pO, pi; char *p; fortp = buf; *p; p++) if{(*p < '0') | | Cp > '9')) *p = ' '; sscanf(buf, "%d%d%d%d%d%d%d" , trep, ihO, thl, ih2, ih3, ipO, ipl) ,- sprintf (pasvhost, "%d.%d.%d.%d",h0,hl,h2,h3) ; data = new tcplthis, pasvhost, pasvport=(256*p0 + pi), crud->status) data->reading = (crud->type == R) ,- data->cooked = 0; ) int ftptask: :partial(1 { if(type) { do { if( !ctl->select() ) return block(state) ; ctl->read(buf, sizeof(buf)) ; strncpy(crud->status, buf, sizeof(crud->status) ) ,- strcatferr, "Nn"); strcatferr, buf); } while(buf[3] == '-' | | !strchr( "0123456789" ,buf[0] )) ; if(buf[0] != CO'+type)) { if(crud->type == R it ! asdir tt param == 6) { data->cooked = ++wasdir; pareun = 10; type = 2; sprintf(buf, "CWD %s", path); ctl->write(bu ) ; return run(state); } else { ws.create(500, "text/html") ; ws.prin ("<HEAD><TITLE>%s</TITLEx/HEAD>" , buf) ; ws. rint("<BODY><Hl>%s</HI><PRE>%s</PRE><BODY>",buf,err) return finish(ws.close( ) ) ,- } irab.cn Mon Mar 20 12:13 : 00 1995 5 } strcpy(err, " " ) ; } switch(param) { case 0 : if ( !ctl->connected( ) ) return finish(fivehundredt "couldn't contact server")) type = 2; param++; break; case 1- ctl->wrιte( "USER anonymous"); type = 3; param++; break; case 2 : sprintf(buf, "PASS %s", crud->auth->from ? crud->auth->from : httpFromO), ctl->wrιte(buf) ; type = 2; para_m++; break; case 3 : ctl->wrιte ("TYPE ι"); type = 2; param++; break; case 4: ctl->wπte( "PASV" ) ; param++; break; case 5 : getpasv( ) ,- switch(crud->type) { case C: case U: spr tflbuf, "STOR %s", path) ; type = 1; param++; break; case R: sprintf (buf, "RETR %ε", path); type = 1; param++ ; break; case D: sprintf (buf, "DELE %s", path); type = 2 ; param = 8, break; default: sprintf (buf, "QUIT") ; break; type = 2; param = 8; break; } ctl->wrιte(buf) ; break, case 6 : if (ctl->hasdata{) ) { ctl->read(buf.sizeof (buf) ) ; ctl->wrιte( "QUIT" ) ; return fιnιsh( fιvehundred(buf) ) , } if ( !data->connected( ) ) return finish(fιvehundred( "couldn' t contact PASV")) ; tot = 0; type = 0; param++; break; case 7 : type = 2 ; if (crud->type != R) { struct rstrand rs; rs.open(crud->sιd) ; int len; while(len = rs.read(buf, sizeof (buf)) ) data->wrιte (buf, len) ; rs .close(0) ; delete data; data = 0; state = twohundredl "%s updated on %s", path, host) ; type = 2; param++; break,- } if(ctl->hasdata() ) { ctl->read(buf, sizeof (buf)) ; if(bu [0] '= '2') { wab.cxx Mon Mar 20 12:13:00 1995 6 ws.forget() ; ws.create(500, "text/html"); ws.print("<HEADxTITLE>%s</TITLEx/HEAD>" , buf) ; ws.print("<BODYxHl>%s</HlxPRE>%s</PRExBODY>" ,buf,err) ; return finish(ws.close() ) ; } else { delete data; data = 0; strncpy(crud->status, buf, sizeof(crud->status) ) ; return finish(state = ws.closet)) ; } } if(data->hasdata() ) { int len; if(wasdir) { if(ltot) { if(strlen(path) > 1 it path[strlen(path)-1] == '/') path[strlen(path)-l] = 'NO'; ws.create(200, "text/html" ) ,- ws.print ("<HEADxTITLE>ftp://%s%s</TITLE>Nn" ,host,path) ws.print("</HEADxBODY><Hl>ftp://%s%s</Hl>" .host, path) char *m = strrchr(path, ' /' ) ; iflm != path) { *m = ' NO' ,- ws.print( "up to <A HREF=N"ftp: //%s%sN">parent</A>directoryNn" , host, path) ; *m = '/ ' ; } ws.prin ("<UL>") ; ) while(data->selectI) ) { len = data->read(buf, sizeof(buf)) ; tot += len; ifden) ws.print("<LIxA HREF=N"ftp://%s%s/%sN">%s</A>Nn", host, path, buf, buf); else { delete data; data = 0; ws.print("</ULx/B0DY>" ) ; param++,- return runIstate = ws.close!) ); } } } else { if(itot) { ws.create(200,guess_suffix(path) ) ,- } while(data->selectI) ) { len = data->read(buf, sizeof(buf1 ) ,- tot += len; ifden) ws.write(buf, len); else { delete data; data = 0; param++,- return runfstate = ws.close)) ); } } } data->statistics(crud->status, 0) ; type = 0; } return block(state) ; case 8: ab.cxx Mon Mar 20 12:13:00 1995 7 strncpy(crud->status, buf, sizeof(crud->status) ) return finish(state) ; case 10: ctl->write("NLST") ; type = 1; param = 6; break; } return run(state); char *http_ti_ne(time_t *) ; time_t parse_http_time(char *); class httptask : public task { Crud *crud; char *method, *url; tcp "sock; struct strandinfo si; char buf[0x800] ; char *location; unsigned long len; wstrand ws; int param; int connected; unsigned long tot; public: httptask(char *, int, char *, char *, Crud *) -httptask() ; partial() ; int Connect() ,- int GetStrandBit() ,- }; int http(Crud "crud, char "method, char *url) ( char *host; int port = 80; char *m; if(m=pmatch("http://" ,url) ) { char *p = strchr(m, ' / ' ) ; host = (p ? (char *)copyn(m,p-m) : copy(m)); url = (p ? p : "/") ; } else { if( Iproxyhost) return ivehundre t"please set a proxy server (Tools->Preferences->General )"). host = copy(proxyhost) ; } if(m = strchrlhost, ':')) { *m++ = 'NO' ; port = atoi(m) ,- ) crud->comm = new httptask(host, port, method, url, crud) ,- myfree(host) ; return 0; ) httptask: :httptask(char "host, int port. ab.cxx Mon Mar 20 12:13:00 1995 8 char *_method, char *_url, Crud *_crud) : task(0) { sock = new tcp(this, host, port, _crud->status) ; sock->verbose = 1; si.type = (char *)0; si.date = si.lastmod = si.expires = 0; si. ocument = (const char *)0; location = (char *)0; param = 0,- method = _method, url = _url; crud = _crud; connected = 0; } httptask: :-httptask() { delete sock; } mt httptask: :partιal () { i ( !connected++) return Connect()',- else { len = sock->read(buf, sizeof(buf)) ; return GetStrandBit() ; } } int httptask: :Connect() { if( !sock->connected() ) return finish(fivehundredt"couldn't find server")) ; sprintf(buf, "%s %s HTTP/1.0", method, url); if( !sock->wπte(buf) ) return finish!fivehundredt"couldn't contact server")); sock->wπte("User-Agent: StraαιdLib/0.1" ) ; sock->wrιte("Accept: */*"); sprintf(buf, "From: %s", crud->auth->from ' crud->auth->from : httpFromO). sock->wrιte(buf) ; sprintf(buf, "Authorization: %s %s", crud->auth->type, crud->auth->data) , sock->wrιte(buf) ,- if(crud->refered_by) { sprintf(buf, "Referer: %s", crud->refered_by) ; sock->write(buf) ; ) if(crud->reload tt crud->sιnce) { sprintf(buf, "If-Modified-Since: %s", http_tιme( (tιme_t *)tcrud->smce) ) ; sock->wπte(buf) ; } if(crud->sid) { rstrand rs; rs.open(crud->sιd) ; if(rs.typeO ) { sprintf(buf, "Content-Type: %s", rs.typeO); sock->write(buf) ; ) sprintf(buf, "Content-Length: %ld" , rs.sizeO); sock->write(buf) ; if( !sock->write(" ■ ) ) { rs.close(0) ; wab.cxx Mon Mar 20 12:13:00 1995 9 return finish(fιvehundred("couldn't contact server")); } t len, tot = 0; while den = rs . read fbuf , sizeof (buf ) ) ) { tot += sock->wrιte (buf , len) ; _ιnfo ( "written %dNn" , tot) ; } _mfo ( "closing . . . " ) ; rs . close ( O ) ; } else { if( !sock->wrιteC") ) return fιnιsh(fivehundred!"couldn' contact server")), } sprintf(crud->status, "connected, waiting for reply"), tot = 0; return block(0); ) static char "skipwhite(char "start) { whileCstart <= 0x20) εtart++; return start; } int httptask: :GetStrandBιtI) { switch(param) { case 0: { char *m; if( (m=pmatch("HTTP/1.0 " ,buf)) it ((si.status = atoι(m)) > 100)) { param++; } else { si.type = copyI"text/html") ,- si.date = tιme(0); si.expires = si.date + 10; si.modifyable = 0, ws.create(tsi, web), if(crud->mfo) return flmshlws.ιnfo() ) , sock->cooked = 0; sock->resetstat() ,- param = 2,- tot += ws.wrιte(buf, len); return ru ( s.snapshot() ) ; } if(si.status == 304 it crud->reload) { strcpy(crud->status, "Not Modified"); return finish(0) , } ) break; case 1: if( !sι.expires) si.expires = (si.lastmod ' fudge(si.lastmod, si.date) si.modifyable = 0; ιf{sι.status == 302) { web.cxx Men Mar 20 12:13:00 1995 10 ws.create(302, location) ; return finish(ws .close ()) ,- ) ws .create(tsi, web); if (crud->info) return finishfws . info I ) ) ; sock->cooked = 0; // header not in statistics... sock->resetstat ( ) ; param++; } else { char *m; if(m=pmatch( "Content-Length: ", buf) ) si.size = atol IskipwhiteIm) ) ,- else if (m=pmatch( "Content-Type: " , buf) ) si.type = copyIskipwhite(m) ) ,- else if (m=pmatch( "Date: " , buf)) si.date = parse_http_time(skιpwhιte (m) ) ; else if (m=pmatch( "Expires :" , buf)) si.expires = parse_http_time (skipwhite (m) ) , else if (m=pmatch( "Last-Modified: " , buf)) si. lastmod = parse_http_tιme (skipwhite (m) ) ; else if (m=pmatch( "Location: " , buf) ) location = copy(skipwhite(m) ) ; else if (m=pmatch( "URI : " , buf)) location = copy(skipwhite(m) ) ; else if (m=pmatch( "X-NaviDoc: " , buf)) si.document = copy(skipwhite(m) ) ; else if (m=pmatch( "Server:" , buf)) if (pmatch( "NaviServer" , skipwhite(m) ) ) si .naviserver = 1; } break,- caεe 2 : sock->statιstιcs (crud->εtatuε, si.size) ,- if I! len) { _info( "HTTP/1.0 %d (%s)Nn", si.εtatuε, s . type); if (si .document) _info( "X-NaviDoc : %sNn", si .document) ; if I ' si . type) si. type = guess_suffιx(url) ; return finishlws.closeI ) ) ; } else { tot += ws.writefbuf, len); return run(ws .snapshot ()) ; ) break,- default : _info( "lousy state!"); *(ιnt *)0 = 0; } return run() ,- } •include <ctype.h> extern "C" { int sock_open (char *, int, char *) ; int sock_connected(int) ; int sock_hasdata(int) ; int sock_write(int, char *, int) ; int sock_read(mt, char *, int); wab.cxx Mon Mar 20 12:13:00 1995 11 int sock_closetint) ; } t tcp: :ιnιtlint port, char *status) { // statistics tO = 0; traffic = 0; tare = 0; if(addr == -1) sock = -1; else { char buf[0x10] ,- sprintftbuf, "%1d.%1d.%1d.%1d", (addr t Oxff000000) » 0x18, (addr t OxOOffOOOO) » 0x10, (addr t OxOOOOffOO) >> 0x08, (addr i OxOOOOOOff) >> 0x00), sock = sock_open(buf, port, status) ,- pos = len = 0; } return sock; void dns(char 'host, char 'status, long 'paddr); tcp: :tcp(task 'par, char 'host, int _port, char *_status) : task(par) { reading = 1; cooked = 1; verbose = 0; port = _port; status = _status; dnslhost, status, iaddr) ,- tcp: :tcp(task "par, long host, mt _port, char *_status) : task(par) { reading = 1; cooked = 1; verbose = 0; min = 0; port = _port; status = ..status; addr = host; int tcp: :connected() return(sock '= -1) ,- tcp: :-tcpt) sock_close(sock) ; int tcp: :wπte(char *str) web. cxx Mon Mar 20 12:13:00 1995 12 { if (verbose) _ιnfo ( "%sNn" , str) , t ret = 0, ret += sock_wrιte(sock, str, strlen (str) ) ,- ret += sock_wrιte (sock, "NrNn", 2), return ret; } mt tcp: :wrιte(char "buf, int len) { return(sock_wrιte(sock, buf, len) ) ,- } int tcp: :hasdata() { return (pos < len ' 1 : sock_hasdata(sock) ) , } // cooked data- if we don't have a certain # of // characters to wait for, then we are waiting for // a newline static t fancydata(char "buf, int pos, mt len, mt m ) { if(mm) return(pos + mm <= len), for nt l = pos; l < len, ι++) ιf(buf[ι] == 'Nn') return 1, return 0; } int tcp: -select() { if(sock == -1 | | 'reading) return 1, if( !cooked) return hasdata() ; if(fancydatadbuf, pos, len, mm)) return 1; if(sock_hasdata(sock) ) { mt aunt = sock_read(sock, lbuf+len, sizeofdbuf)-len) traffic += amt; if('aunt || fancydatadbuf, pos, len += amt, mm)) return 1; } return 0; } int tcp: :rime(char "buf, mt max) { int c, l, if(poε == len) { strcpylbuf, "") ; return 0; } for ') { w i e it isspace uf[l-l] ) ) 1-- ; buf[ι] = 'NO',- web. cxx Mon Mar 20 12 : 13 : 00 1995 13 goto done; } buf[ι] = c; ) while(pos '= len it c '= 'Nn') { c = ibuf[pos++] ; } done: • if(verbose) _mfo("%sNn" , buf) ; if{pos == len) pos = len = 0; return I, } int tcp: :read{char *buf, mt max) { if(cooked it !mιn) return rlinetbuf, max); if(hasdatal) ) { if(pos < len) { if(len - pos < ma_x) max = len - pos, memcpy(b f, ib f+pos, max) ; pos += max; return max, ) else { int amt = sock_read(sock, buf, max) ; traffic += a t; re urn amt,- } } return 0; ) int tcp: :partial () { if (prog) return 0; /* we've already reported this */ ιf('tθ) { if( 'sock ii addr) mit tport , status ) , if (sock == -1 | | sock it sock_connected(sock) ) { tO = millisec ( ) ; return 1 ; } return 0 , } return select() ,- } /*""""""/ •include < ιme.h> •include <strιng.h> /* strongly influenced by HTSUtils.c from CERN */ static int make_numIchar *s) { if (*s >= '0' it *s <= '9' ) return 10 * Cs - '0') + *(s+l) - '0' ; else returr * (s+1) - '0' ; ) wab. Mon Mar 20 12:13:00 1995 14 static char *month_nameε [12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun" "Jul", "Aug", "Sep", "Oct 1 , "Nov", "Dec" static int make_month(char *s) { int i ,- "ε = toupper(*s) ; "(s+1) = tolower(* (ε+1) ) ; *(s+2) = tolower(* (s+2) ) ; for (1=0; ι<12, ι++) if ( !strncmp(month_names[l] , s, 3)) return l; return 0; tιme_t parse_http_tιme(char "strl { char * ε,- struct tm tm, tιme_t t; if ( 'str) return 0; if ((s = strchr(str, ', '))) { Thursday, 10-Jun-93 01.29:59 GMT */ s++ , or: Thu, 10 Jan 1993 01:29:59 GMT */ while (*s tt *s==' ') s++, if (strchrls, '-' ) ) { /* First format */ if ( dnt)strlen(s) < 18) ( return 0, } tm.tm_mday = make_num(s) , tm.tm_mon = make_month(s+3) , tm.tm_year = make_num(s+7) ; tm.tm_hour = make_num(s+10) ,- tm.tm_mm = make_num(s+13) ,- tm.tm_sec = make_num(s+16) ,- else { /* Second format if ( dnt)strlen(s) < 20) return 0; } tm.tm_mday = make_num(s) ; tm.tm__mon = make_month(s+3) ; tm.tm_year = (100*make__num(s+7) 1900) + make_num(ε+9) , tm.tm_hour = make_num(s+12) ; tm.tm_mιn = make_num(s+15) ; tm.tm_sec = make_num(s+18) ; } ) else { /* Try the other format Wed Jun 9 01:29:59 1993 GMT */ s = str; while (*s tt *s==' ') s++, if ( dnt)strlen(s) < 24) ( return 0; ) tm. m_mday = make_nu (s+8) , wab.cxx Mon Mar 20 12:13:00 1995 15 tm.tm isdst = /" * What a pain it lε to get the timezone correctly */ •if defιned(sun) it !defιned( εvr4 ) t = tιmegm(ttm) ,- •else t = mktime(ttm) ; •if definedISIGTSTP) tt IdefinedlAIX) tt !defmed( sgi) /"BSD,have tm_gmtoff*/ { tιme_t cur_t = time(NULL); struct tm * local = localtime(tcur_t) ; t += local->tm_gmtoff; } •elif !defined(macintosh) /* SysV */ /* [daveb] does Mac have a concept of timezone' */ { t += timezone * 60; } •endif •endif return t; } char *http_tιme(time_t *t) { static char buf[40] ; /* Mac doesn't know about time zones, but is kind enough to provide a * gmtimeO call, which always returns NULL and causes the next statement * to lock the machine. Thanks, Macintosh! */ •if 'defined(macintosh) strftιme(buf, 40, "%A, %d-%b-%y %H:%M:%S GMT", gmtιme(t)); •else strftimelbuf, 40, "%A, %d-%b-%y %H:%M:%S", localtime(t) ) , •endif return bu ; } tιme_t fudge(tιme_t lastmod, tιme_t date) { if(!date || date < lastmod) date = tιme(O) ; wab.cxx Mon Mar 20 12:13:00 1995 16 return date + (date - lastmod) ; } class smtptask : public task { Crud "crud; char *user, *host; char *subj, "body; char *p; tcp "sock; char buf[0x100] ; char err[0x1000] ,- int type,- rstrand "rs; εtrandinfo si; public: smtptas (char *, char *, char *, char *, Crud *), -smtptask() ; int partial() ; ); int smtptchar *_user, char *_host, char *_sub 3 , char *_body, Crud *crud) { crud->comm = new smtptask(.user, ..host, _sub 3 , _body, crud); return 0,- ) smtptaεk: :smtptask(char *_user, char *_host, char *_subj , char *_body, Crud *_crud) : task(0) { user = copy(_user) ; hoεt = copy(_host) ,- sub 3 = copy(_subj) ; body = copy(_body) ; crud = _crud; εock = new tcplthiε, host, 25, crud->status) ,- sock->verbose = 1; strcpy(err, "" ) ; } smtptask: :-smtptask( ) { delete sock; myfree(user) , myfree(host) , myfree(subj) , myfree(body) ; } int smtptask: :partial() ( if(state) { sock->read(buf, sizeof(buf)) ,- strncpy(crud->status, buf, sizeof(crud->status) ; if(buf[3] == '-') ( strcat(err, buf) ; strcat(err, "Nn") ; returnIrun(state) ) ; } if(buf[0] != type+'0' ) { wstrand ws; ws.create(500, "text/html"),- wab.cxx Mon Mar 20 12:13:00 1995 17 ws.prmt("<HEADxTITLE>%s</TITLEx/HEAD>", buf) ; ws.print("<BODYxHl>%s</HlxPRE>%s</PRExBODY>" ,buf,err) return finish(ws.closet)) ,- ) else strcpy(err, "") ; } switch(state) { case 0: if ( !sock->connected() ) return finish(fivehundredt"couldn't contact server")); type = 2; state++; break; case 1: sprintf(buf, "VRFY %s", user); sock->wrιte(buf) ; state++; break; caεe 2 : sprintf(buf, "MAIL FROM: %s' , httpFrom(l); sock->wrιte(buf) ; state++; break; case 3: sprintf(buf, "RCPT TO: %s", user), sock->wrιte(buf) ,- state++; break; case 4: type = 3; sprintf(buf, "DATA"); sock->wrιte(buf) ; state++; break; case 5: { tιme_t now = tιme(O), sprintf(buf, "Date: %s", http_tιme(tnow) ) , sock->wrιte(buf) , sprintf(buf, "From: %s", httpFrorr( ) ) , sock->wrιte(buf) ; sprintf(buf, "To: %ε", user), sock->wrιte(buf) ; if(sub:) sprmtfibuf, "Subject: %s", sub 3 ) , sock->write(buf ) ; sock->wrιte ( "Content-Type: text/pla ") ; } else { sprmtf(buf, " Content- ype : text/html"); sock->wrιte(buf ) ; ) } if (body) ( char *q = p = body; do { if (*p == ' .') sock->wrιte ( " . " , 1 ) ; for(q=p; *q '= 'Nn' ii *q '= 'NO'; q++); sock->wrιte(p, q-p) ; sock->wrιte C " ) ; p = q+1; ifCq == 'NO') break ; } whileCq '= 'NO' ) ; } else i (crud->sιd) { rstrand rs ; char buf [0x400] , web.cxx Mon Mar 20 12:13:00 1995 18 rs.open(crud->sιd) ; while(rs.getline(buf, sizeof (buf)) '= -1) { if(buf[0] == '.') { sock->wrιte(" ",D; ) sock->wπte(buf) ; } rs.close(0) ; } sock->wrιte("."); type = 2; state++; break; case 6: sprintf(buf, "QUIT"); sock->wrιte(buf) ; state++; break; case 7: return fιnιsh(twohundred("mail sent to %sθ%s", user, host)) ) return run(state); int) ; -poptask() ; mt partial() ; }, extern "C" { int HTUU_decode(char *, unsigned char *, int); } int popcrudtCrud "crud) { if(crud->type '= R || !crud->url) return fivehundredt"not yet implemented"); char "user = pmatch("pop ", crud->url); char *host = strchr(user, '@' ) ; if( 'host) return fivehundredt"use as pop:userθhost") *host++ = 'NO' ,- if(strcm (crud->auth->data, "")==0) { wstrand ws; ws.create(401, "*/*"); return ws.close() ; } wab.cxx Mon Mar 20 12:13:00 1995 19 char *number = strchr(host, '/') ; if (number) *number++ = 'NO'; char buf [0x100] ,- buf [HTUU_decode(crud->auth->data, (unsigned char *)buf, sizeof (buf)) ] = 'NO' char "pass = strchr(buf, ':'); *pass++ = ' NO' ; crud->comm = new poptask(crud, host, user, pass, (number ? atoi (number) : 0)); return 0; } poptask: :poptask(Crud *_crud, char "_host, char *_user, char *_pass, t _val) : task(0) { crud = _crud; host = copy(_host) ; user = copy(_user) ; pass = copy(_pass); val = _val; cur = max = 0; sock = new tcp(this, hoεt, 110, crud->status) ; sock->verbose = 1; } poptask: : -poptask( ) { delete sock; myfree(host) ; myfree(user) ; myfree(pass) ; } char "replyto(char "from) { static char buf [0x100]; strcpylbuf, from); char *p, *q; if{(p = strchr(buf, '<')) it (q = strrchr(buf, ' ' ) ) it q > p) { /* From: foo bar <foo.barβbletch.com> */ *q = 'NO' ; P++; } else { /* From: foo.barβbletch.com (foo bar) */ p = pmatch( "From: ", buf); for(q = p; *q != ' ' ; q++); *q = 'NO' ; } return p; } int poptask: :partial () { if (state) { sock->read(buf, sizeof (buf)) ,- if(state != 5) { strncpy(crud->status, buf, sizeof(crud->status) ) ; if(buf[0] == '-') { wstrand ws; if (state > 3) { wab. cxx Mon Mar 20 12 : 13 : 00 1995 20 ws.create(500, "text/html"); ws.prmt ("<HEADxTITLE>%s</TITLEx/HEAD>" , buf) ws.prmt I "<BODYxHl>%s</HlxBODY>" , buf) ; } else { ws.create(401, "*/*"), ) sock->wrιte ( "QUIT" ) ; return finish(ws.closet )) , } } ) switch(state) { case 0: if ( 'sock->connected( ) ) return finishtfivehundredl "couldn' t contact server") ), state++; break, case 1 sprintf (buf, "USER %s", user) , sock->wrιte (buf) ; state++; break; case 2 : sprintf (buf, "PASS %s", pass) , sock->wπte (buf) ; state++; break; case 3 : iff 'val) { sock->wπte( "STAT" ) ; ws.create(200, "text/html" ) ,- ws.prmt I "<HEADxTITLE>%s's maιl</TITLEx/HEAD>" , user), ws.print ( "<BODYxHl>new messages</Hl><UL>" ) ; state=6 ,- } else { sprintf (buf, "RETR %d' , val), sock->wπte(buf) , ws.create(200, "text/plain" ) ,- state++, } break,- case 4 : state++, break, case 5 if (pmatch( "From- " ,buf) ! strcpylfrom, buf1 ; else if (pmatch("Subject: " ,buf) ) strcpy(sub 3 , buf) ; else if(pmatch! "Date: ", buf) ) strcpyldate, buf) ; else if (strcmp(buf, " . " ) == 0) { sock->wrιte("QUIT") , return fιnιsh(ws .close( ) ) ; } ws.prmt ( "%sNn" , buf) ; break; case 6. if (cur == 0) { mt nu , size; sscanflbuf, "+0K %d %d" , inu , isize) ; max = num; } cur++, lf (cur > max) { sock->wrιte ( "QUIT" ) ; ws . prmt ( "</ULx /B0DY> " ) , return f mish (ws . close ( ) ) , web. cxx Mon Mar 20 12 : 13 : 00 1995 21 } else { sprintf (buf , "TOP %d 0 " , cur ) ; strcpy (subj , " " ) ; sock->write (buf ) ; } state++ ; break ; case 7 : if (pmatch ( " From : " , buf ) ) strcpy(from, buf); else if(pinatchl"Subjec :",buf) ) strcpy(subj, bu ) ; else if(pmatch("Date:",buf) ) strcpy(date, buf); else if(strcmplbuf, ".") == 0) { ws.print("<LI><BxA HREF=pop:%sβ%s/%d>%s</Ax/BxBR>%s<BR>%s" , user.host,cur, *subj?sub : " (no sub ect) " ,from,date) ; ws.print ("<BRxIxA HREF=mail o:%s>reply.. _</Ax/I>" ,replyto(from) ) sock->write("NOOP" ) ; state—; ) break; } return run(state) ; long *) ; char 'name; long addr; }; struct _nc 'namecache = (struct _nc *)0; static int next; extern *C" { char 'nameserver = "198.68.146.18"; long numeric_host(char *) ; ) void dnstchar 'host, char 'status, long 'paddr) { int i; long number = numeric_host(host) ,- if (strcm (nameserver, "0.0.0.0")==0) { sprintf (status, "please set your nameserver") 'paddr = -1; return; web.cxx Mon Mar 20 12:13:00 1995 22 } if (number) { 'paddr = number; return; ) lf ( !na ecache) { naunecache = (struct _nc *)myalloc (sizeof (struct _nc) * CSIZ) ,- ford = 0; 1 < CSIZ; 1++) namecache[l] .naune = (char *)0; next = 0; } ford = 0; l < CSIZ; ι++) { i (namecache[i] .name tt strcmpfnamecache[l] .name, host)==0) { *paddr = namecache [l] .addr,- - return; } } new dnstasklhost, status, paddr), } dnstask: : nstask(char *_host, char *_status, long *_paddr) : task(O) { host = copy(_host); status = _status; paddr = _paddr; sock = new tcp(thιs, numeπc_host (neuneserver) , 53, status) ; sock->cooked = 0; } dnstask: : -dnstask() { delete sock; myfree(host) ; } static char "writeshort (char *buf, t n) { unsigned char *p = (unsigned char *)buf; p[0] = n » 0x8, p[l] = n t Oxff; return buf+ ; } // foo-> 3foo static char *wrιtelabel (char *buf, char *str) { mt l = strlen(str); *buf++ = I; whileCstr) *buf++ = *str++; return buf; } // foo.bar -> 3foo3bar0 static char *encode(char *buf, char *name) { char "p,- while (name) ( p = strchr (name, ' . ' ) ; if (P) *p = 'NO'; buf = writelabel (buf, name) ; name = p; iflp) { web.cxx Mon Mar 20 12:13:00 1995 23 *P = naune++; } } return writelabel (buf, ""), } static mt writequery(char *buf, char *host) { static int seq = Oxdead, char *p = buf; // header p = writeshort (p, seq++ ) ; p = writeshortlp, 0x0100) ; // recursive QUERY p = writeshortlp, 0x1) ; // 1 question p = writeshortlp, 0) ; // no answers p = writeshortlp, 0) ; // no nameservers p = writeshortlp, 0) , // no additionals // question p = encodelp, host); p = wrιteshort(p, 0x1), // TYPE = A p = writeshortlp, 0x1), // CLASS = IN return p - buf. ) static char 'decode (char *buf, int 'done) { if ((bu 10] i OxcO) == 0) { // inline ♦ done = ibuf [0] ; return buf + 1 + buf[0]; } // it's a pointer 'done = 1, return buf+2; } static char *readquery(char *buf) { for(done = 0; idone; buf = decode (buf, tdone) ) , return buf + 4; // skip TYPE, CLASS } static char 'readshort (char *buf, int *val) { if (val) { unsigned char *p = (unsigned char *)buf, "val = (p[0] « 0x8) + p[l] , } return buf + 2 , } static char *readlong(char "buf, long *val) { if (val) { unsigned char *p = (unsigned char *)buf; "val = ((unsigned long)p[0] << 0x18) + ((unsigned long)p[l] << 0x10) + ((unsigned long)p[2] « 0x3) + ((unsigned long)p[3] << 0x0) ) return buf + , ) web.cxx Mon Mar 20 12:13:00 1995 24 static long readanswer (char *buf) { int done; int type, len; for (done = 0; Idone; buf = decode (buf, idone)); buf = readshort (buf, ttype) , // TYPE buf = readshort (buf, NULL); // CLASS buf = readlong(buf, NULL); // TTL buf = readshort {buf, tlen); // RDLEN if (type == 1) { long ret; readlong (buf, iret) ; return ret; } buf += len; return readanswer (buf) ; int dnstask: :partial ( ) { switch(state++) { case 0: if( !sock->connected() ) { sprintf (status, "couldn' t find nameserver"); •paddr = -1; return finish(O); } sprintf(status, looking up '%s' ... " , host) ; writeshort (Ibuf, len = writequery(buf, host) ) sock->write(lbuf 2); sock->write (buf, len) ; sock->min = 2 ; return run(state case 1: sock->rea (Ibuf, 2) readshort (Ibuf, tlen) ; sock->min = len; return run(state); case 2 -. sock->read(buf, len); if (buf [3] i Oxf | | buf [7] = = 0) // failure or no answer *paddr = -1; else { char *p = buf + 12; // skip header if (buf [5]) p = readquery(p) ,- 'paddr = readanswer(p) sprintf(status, "found '%s' at %ld.%ld.%ld.%ldNn", host. Cpaddr i Oxff000000) » 0x18, Cpaddr i OxOOffOOOO) » 0x10, Cpaddr i OxOOOOffOO) » 0x08, ("paddr t OxOOOOOOff) » 0x00) ; // remember this... next %= CSIZ; myfree(naunecache[next] .name) ; namecache[next] .name = copy(host) ; namecache[next++] .addr = "paddr; ) return finish(O); } // shouldn't happen wab.cxx Mon Mar 20 12:13:00 1995 25 return finish(O) ; ) xcc Wad Mar 22 14:53:18 1995 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •include <xvt.h> •include "xcomm.h" •include "lfunc.h" int _info(char *fmt,...); static in_name _getaddrbyname(const char "name) { •define CSIZ 0x10 static struct _nc { char "name; in_name addr; } "namecache; static struct hostent he; static int next; int i; LPhostent dstHost; if( !namecache) { namecache = myalloc(sizeo (struct _nc) * CSIZ); ford = 0; l < CSIZ; i++) naunecache[i] .name = (char *)0; next = 0; } ford = 0; i < CSIZ; i++) { if<namecache[i].name it strcmp(namecache[i] .name, naune) = return namecache[i] .addr; } } _info ( ">»> miss %s", name); if ((dstHost = gethostbynamef (char "(name)) == NULL) { _info(" 0!Nn"); return (in__name)NULL; ) next %= CSIZ; myfree (naunecache[next] .name) ,- namecache[next] -name = copy(name) ; namecache[next] .addr = * ( (LPin_naune) (dstHost->h_addr) ) , _info (" %xNn" , namecache[next] .addr) ,- return namecache [next++] .addr,- } in_name mygrabaddr(char "host) { 4) } return INADDR_NONE; long numeric_host(char "host) { •if XVT_OS_ISUNIX in_name IP = ntohl(inet_addr(host) ) ; return (IP == INADDR_NONE ? 0 : (long)IP) •elif XVT_OS == XVT_OS_MAC xcoam.c Wad Mar 22 14:53:18 1995 2 struct in_addr host_addr = inet_addr(host) ,- /* inet_addr returns a long not a struct i n_addr */ in_name IP = ntohl(host_addr.s_addr) ,- return (IP == INADDR_NONE ? 0 : (long) IP); •else in__naune IP = mygrabaddr(host) ; return (IP == INADDR_NONE ? 0 : Ilong)IP); •endif ) int sock_openIchar "host, int port, char "status) { in_name ds11P; int s,- struct sockaddr__in sin; WSADATA wsad; struct in_addr host_addr; i (WSAStartup!0x101, twsad) ) { IErrorI"couldn't start WinSock 1.1"); return NULL_S0CKET; } /* resolve destination host name */ •if XVT_0S != XVT_OS_MAC if ( (dstIP = inet__addr(host) ) == INADDR_NONE) { •else host_addr = inet_addr(host) ; if KdstlP = host_addr.s_addr) == INADDR_NONE) { •endif dstIP = _getaddrbyname(host) ,- if (dstIP == (in_name)NULL) { if(status) strcpy(status, "couldn't resolve host"); return NULL_SOCKET; ) } /* open local socket */ if (Is = SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP) ) == NULL_SOCKET) ( IError("couldn't open local socket"); return NULL_SOCKET; } else { u_long arg = 1; ioctlsocketfs, FIONBIO, (caddr_t)targ) ,- ) /* connect remote socket */ sin.sin_fa___.ily = AF_INET; sin.sin_port = htons(port) ,- sin.sin_addr.s_addr = dstIP; if (CONNECT(s, (LPsockaddr_in)isin, sizeof(sin)) != 0) { if(WSAGetLastErrorO != WSAEWOULDBLOCK it WSAGetLastError() != WSAEINPROGRESS) { closesocketIs) ; if(status) sprintf(status, "failed to connect to %s:%d", host,port) ; return NULL_SOCKET; } ) if(status) sprintf(status, "connecting to %s:%d", host, port); i. c Wad Mar 22 14 : 53 : 18 1995 return ε ; } int sock_connected ( int sock) { struct timeval tv = { 0 , 0 } ; fd_set w; FD_ZER0 ( iw) ,- FD_SET ( sock , iw) ; return SELECT(sock+1, NULL, tw, NULL, ttv); ) int sock_hasdata(int sock) { struct timeval tv = {0,0}; fd_set r; FD_ZERO(ir) ; FD_SET(sock, ir); return SELECT(sock+1, tr, NULL, NULL, ttv) ; } int sock_write(int sock, char "buf, int len) { char *p = buf; int sent, left = len; if(ilen) return 0; whiledeft) { sent = SENDtsock, p, left, 0); if(sent > 0) { p += sent; left -= sent; ) else if(sent == 0 | | WSAGetLastError( ) == SAEWOULDBLOCK) Pause(left) ,- } else { printf(">>>> socket write error! errno = %d <<<<", WSAGetLastError()) ; return len - left; } } return len; } int sock_read(int sock, char "buf, int len) { int got = RECVtsock, buf, len, 0); if(got < 0) { printf(">>>> socket read error! errno = %d <<<<", WSAGetLastError()) ; return 0; ) return got; ) void sock_close(int sock) { closesocket(sock) ; WSACleanup() ; } char "mailaddr = NULL; char *httpFrom() { xcαnm.c Wad Mar 22 14:53:18 1995 4 static char buf[0x100], •if XVT_OS == XVT_OS_MAC static char "UserName = (char *)NULL; •endif ifI 'mailaddr) { WSADATA wsad; LPhostent he, if (WSAStartupl0x101, twsad)) { IError("couldn't start WinSock 1 1"), return " " , } •if XVT_OS == XVT_OS_MAC if ('UserName) { UserName = getloginO, if ( 'UserName) UserName = "wwwUser" ; } •endif gethostnametbuf, sizeof(buf)) , he = gethostbyname(buf) , sprintf(buf, "%sβ%s", UserName, (he ' he->h_name somewhere")) mailaddr = copy(buf), WSACleanup!) , ) return mailaddr, xdoc .c Thu Mar 2 19 : 00 : 10 1995 1 / * Copyright 1994-1995 NaviSoft , Inc . All rights reserved. * / •include <stdio . h> •include <string . h> •include "xlocal . h" •include "weblet . h" char *fsys_isdoc(char *pa h) { if(fsys_isdir(path) ) { static char buf[0x100],- fεys__build_naune(path, WEBLET_MARK, buf,sizeof(buf)) ; if( sys_exists (buf) ) return buf; } return (char *)0; } static int rmasset(char *deldir, char *name) { if ( ifsys_isdir(neune) ) { _info("delasset: %sNn", name); fsys_delete(name) ; ) return 0; } int fsys_rmdoc(char *name) { fsyε_iterate(name, tint C) (struct cstr *, char *))rmasset, name) ,- return fsys_rmdir(name) ; } char *fsys_docfor(char "name, char "base) { static char buf[0x100]; fsys_replace_name(name,WEBLET_MARK,buf.sizeof(buf) ) ,- if (fsys_exists(buf) ) { if(base) strcpytbuf, base); *fsys_nametail(buf) = 'NO'; return buf; ) return (char *)0,- xloca .c Thu Mar 23 13:10:05 1995 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. •include <assert.h> •include <xvt.h> •if XVT_0S == XVT_0S_MAC # include <ctype.h> # include <string.h> # include <Strmgs . h> * include <Fιles.h> # include <pascal.h> /* for PtoCstrl) * include <0SUtιls.h> # include <Folders.h> •else # include <sys/stat.h> •endif •include "xlocal.h" •if XVT_OS_ISUNIX char dιr_char = '/ ' ; •elif XVT_0S_IS_WIN0S char dιr_char = 'NN'; •elif XVT_OS == XVT_0S_MAC char dιr_char = ' : ' ; •endif static t mystrncasecmp(const char *sl, const char *s2, size.: n) { mt chl, ch2,- while ( n— > 0 ) { chl = *sl++; ch2 = *s2++; if I ιsupper(chl) ) chl = tolowerIchl) ; if ( lsupper(ch2) ) ch2 = tolower(ch2) ; if ( chl'=ch2 ) return! chl-ch2 ); if I chl==0 ) return 0; /* Match "/ ) return 0,- } t XVT_CALLC0NV1 f sys_ιs_fullurl (char "name ) { char "p ; if ( strncmplname, "mailto: ",7) == 0 | strncmplname, "pop: " ,4) == 0 | | strncmplname, "news: ",5) == 0) return 1; if ( ( pt = strstr(name, "://") )==NULL /* Used 3 ust to check for this, then someo ne did /cgi/foobar/http://spam */ return 0; if ( pt>strchr(name, '/' ) ) return 0 return 1 int XVT_CALLCONVl fsys_ιs__url(char 'name) { char *pt; if ( strncmplname, "mailto: ",7) == 0 | strnciπptname, "pop: " ,4) == 0 | | strncmptname, "newε: " , 5) == 0) return 1; if (( pt = strεtrlname, " :/" ) )==NULL ) /* Used ^us to check for this, then someo xlocal . c Thu Mar 23 13 : 10 :05 1995 2 ne did /cgi/ foobar/http / /spam * / return 0 , if ( pt>strchr (name, ' / ' ) ) return 0 , return 1 , } int fsys_ιs_absolute(const char "name) { •if XVT_OS_ISUNIX return( *name==dιr_char ) •elif XVT_OS == XVT_OS_MAC /* Relative files must have dιr_char as the leading char or else they * can't have dιr_char anywhere */ if ("name == dιr_char) return (0) , return (strchrlname dιr_char) ' 1 0), •elif XVT_OS_IS_WINOS /* absolute == a N ' */ return (named] == ' ' it name [2] == dιr_char) •else return ( 1 ) /* */ •endif } char * XVT_CALLC0NV1 fsys_get_absolute_na_me (char "name, char "result, t rsiz) < /* result may be the saune as name */ char buffer[1000] , DIRECTORY dir, if ( fsys_ιs_url (name) ) { /* It better be absolute, anyway we can't fix it up */, } •if XVT_OS_ISUNIX else if ( ' fsys_ιs_absolute(name) ) { static char dirname [1024] char "pt, "spt, "rpt "bpt if ( dirname [0]==' NO' ) { xvt_fsys_get_default_dιr(tdir) xvt_fsys_convert_dιr_to_str (tdir.dirname, sizeof (dirname) ) } strcpy(buffer,dirname) , if ( buffer[strlen (buffer) -1] '='/' ) strcat (buffer, "/") , strcat(buffer,name) , /* Normalize out any */ spt = rpt = buffer, while ( *spt'='N0' ) { if ( *spt=='/' ) ++spt, for ( pt = spt, *pt'='N0' it *pt'='/', ++pt ), if ( pt==spt ) /* Found // in a path spec reduce to / (we've*/ strcpy(spt,pt) , /* skipped past the // of the machine name) */ else if ( pt==spt+l tt spt[0]==' ' ) /* Noop */ strcpy(spt.pt) , else if ( pt==spt+2 ii spt[0]==' ' tt spt[l]==' ' ) { for ( bpt=spt-2 , bpt>rpt tt *bpt '='/', --bpt ), if ( bpt>=rpt ii *bpt=='/' 1 { strcpy(bpt,pt) , spt = bpt, } else { rpt = pt, spt = pt xlocal.c Thu Mar 23 13:10:05 1995 3 } } else spt = pt; } name = buffer; ) •elif XVT_OS == XVT_OS_MAC else if ( ! fsys_ιs_absolute(name) ) { static char dirname[1024] , if ( dιrname[0]=='N0' ) { xvt_fsys_get_dιr(tdir) ; xvt_fsys_convert_dιr_to_str(tdir,dirname,sizeof(dirname) ) , } strcpy(buffer.dirname) ; /* We have a ' ' terminated dir, so deal with an initial ' ' name */ if ("name == dιr_char) name++; strcat(buf er,name) , name = buffer,- ) •elif XVT_OS_IS_WINOS else { char *wιn_get_absolute_name(char *, char *, int), return wιn_get_absolute_n_une(name, result, rsiz), } •else /* ' ' ' It would be nice to have, but we can pretty well make do with */ /* relative names, sometimes we'll get bugs though */ •endif if (result'=name) { strncpy(result,name,rsiz) , result[rsιz-l]='N0' , } return(result) ; ) int xvt_fsys_str_to_fε(char "name,FILE_SPEC *fε) { char "pt, pt = εtrrchr(name,dιr_char) , if ( pt==NULL ) { xvt_fsyε_get_dιr(ifs->dιr) , strcpy(fs->name,name) , } else { "pt = 'NO' ; xvt_fsys_convert_str__to_dιr(name,tfs->dιr) ; *pt = dιr_char, strcpyffs->name,pt+l) ; ) return(1) ,- ) int xvt_fsys_str_to_absfs(char *name,FILE_SPEC *fs) { char buffertlOOO] ,- return xvt_fsys_str_to_fs(fsys_get_absolute_name(name,buf er,sizeof(buffer) ) , fs) , } mt sys_get_desktop ( char dt [ ] ) { •if XVT_OS == XVT_OS_MAC Str255 volName; short vRef, rc; xlocal.c Thu Mar 23 13:10:05 1995 long avail; short 'BootDrive = (short *)0x0210, rc = GetVInfo('BootDrive, volName, tvRe , tavail) ; if Crc) { strcpy(dt, PtoCstr(volName) ) ; strcat(dt, " :Desktop Folder") ,- return 1; return •endif •if XVT_OS == XVT_OS_MAC mt fsys_ιεvoi (char 'file) /* address of a QHdr structure */ qhp= GetDrvQHdr( ) ; /* address of queue header */ qep = (DrvQEl *)qhp->qHead; /* address of a queue element */ for (qep = (DrvQEl * ) qhp->qHead; qep ' = NULL ; qep= ( DrvQEl * ) qep->qLmk ) rc = GetVInfo ( qep->dQDπve , volNaune , tvRef , tavail ) ; if ( i re ) { i f ( ! strcmp ( file , PtoCstr (volName) ) ) return 1 ; } } return 0 ; •endi f int fsys_ιsdιr(char "file) { •if XVT_OS__ISUNIX char buffer[1000] ,- /* xvt way is just too slow */ sprintf(buffer, "%s%c.",fιle,dιr_char) ; returnt access{buffer,0)==0 ) ,- •elif XVT_OS_IS_WINOS struct _stat buf; int statres; char *p = file + strlenlfile) - 1; char foo[0x10] ,- if(strcmp(file+1, " :NN")==0) { strcpytfoo, file) ; εtrcat(foo, "."),- p = file = foo; } ifCp == 'NN' ) *p = 'NO' , statres = stattfile, ibuf); ifCp == 'NO') *p = 'NN'; if(statres == -1) return 0; return (buf.st_mode t _S_IFDIR) ; •elif XVT_OS == XVT_OS MAC xlocal.c Thu Mar 23 13:10:05 1995 5 FILE_SPEC fs; char *p = file + strlen(fιle) - 1, if (p < file) /* zero-length file name */ return 0, if (*p == ' ') { if (p == strchr(fιle, ' ')) { /* volume name (only ' ' is trailing) */ char voi[256] ; strcpylvol, file), vol[strlen(vol)-l] = 'NO', /* get rid of ' ' */ return fsys_ιsvol(voi) , } else { /* badly terminated dir name */ *p = 'NO', ) } xvt_fsys_str_to_fs(flie, ifs), if ( 'fsys_exιsts(flie) ) return 0, return xvt_fsys_get_fιle_attr(ifs, XVT_FILE_ATTR_DIRECTORY) , •else FILE_SPEC fs; char *p = file + strlen(fιle) - 1, if (p < file) /* zero-length f le name */ return 0, xvt_fsys_str_to_fs(flie, tfs) , if ( 'xvt_fsys_get_fιle_attr(ifs, XVT_FILE_ATTR_EXIST) ) return 0, /* directory check barfs if file doesn't exist*/ return xvt_fsys_get_fιle_attr(tfε, XVT_FILE_ATTR_DIRECTORY) , •endif ) int fsys_exιsts(char *fιle) { •if XVT_OS_ISUNIX I I XVT_OS_IS_WINOS /* xvt way is 3 ust too slow */ return( access(file,0)==0 ), •elif XVT_OS == XVT_OS_MAC OSErr lErr; Str255 pfile, FSSpec spec; strcpy((char *)pfιle, file), CtoPstrI (char *)pfιle), lErr = FSMakeFSSpec(0,0,pflie,tspec) , return ( 'lErr) ; •else FILE_SPEC fs, xvt_fsys_str_to_fs(flie, tfs), return xvt_fsys_get_fιle_attr(ifs, XVT_FILE__ATTR_EXIST) , •endif } mt fsys__modιfyable(char "file) { •if XVT_OS_ISUNIX 11 XVT_OS_IS_WINOS return! access(file,02)==0 ), •elif XVT_OS == XVT_OS_HAC OSErr lErr; xlocal.c Thu Mar 23 13:10:05 1995 6 Str255 pfile; FSSpec spec; strcpy( (char *)pfile, file); CtoPstrI (char *)pfile); iErr = FSMakeFSSpec(0, 0,pfile,ispec) ; return ( !iErr) ; •else FILE_SPEC fs; xvt_fsyε__εtr_to_fs(file, tfs); return xvt_fsys_get_file_attr(ifs, XVT_FILE_ATTR_WRITE) ; •endif } int fsyε_modifyabledir(char "file) { char buffer[1024] , "pt, *pt3; if I fsys_is_url(file) ) /* No concept of directory in an URL */ return 0; strcpy(buffer, f le) ; •if XVT_OS_ISUNIX pt3 = pt = strrchr(buffer, '/') ,- if ( pt==NULL ) strcpy(buffer, " ." ) ; else *pt= ' N0 ' ; •elif XVT_OS_IS_WINOS pt = strrchr (buf fer, ' N N ' ) ; pt3 = strrchr (buf fer , ' / ' ) ; if ( pt==NULL | | (pt3 ! =NULL ScSc pt3>pt ) ) pt = pt3 ; i f ( pt==NULL ) strcpy(buffer, " . " ) ; else *pt='N0' ; •elif XVT_0S == XVT_OS_MAC pt3 = pt = strrchr(buffer, ':') ; if ( pt==NULL ) strcpy(buffer, " . " ) ; elεe *pt='N0'; •endif return( fsys_modifyable(buffer) ) ,- } int fsys_readable(char "file) { •if XVT_OS_ISUNIX I I XVT_OS_IS_WINOS return( access(file,04)==0 ) ,- •else FILE_SPEC fs; xvt_fsyε_str_to_fs(file, tfs); return xvt_fsys_get_file_attr(ifs, XVT_FILE_ATTR_READ) ; •endif } int fsys_size(char "file) { FILE_SPEC fs; xvt_fεys_str_to_fs(file, ifs); return xvt_fsys_get_file_attr(ifs, XVT_FILE_ATTR_SIZE) ; } xlocal . c Thu Mar 23 13 : 10 : 05 1995 7 mt fsys_lastmod (char *fιle) { FILE_SPEC fs , xvt_fsys_str_to_fs ( f lie , tfs ) ; return xvt_fsys_get_fιle_attr(tfs, XVT_FILE_ATTR_MTIME) ; ) int fsys_delete(char *fιle) { •if XVT__OS_ISUNIX I I XVT_OS_IS_WINOS /* xvt_fsys_rem_file does not return an error status, instead it pops up */ /* an obnoxious dialogue if the file doesn't exist */ return! unlink! file )), •else FILE_SPEC fs; xvt_fsys_str_to_fs(flie, tfs) ; return xvt_fsys_rem_fιle(tfs) ; •endif ) void fsys_browse_desktop(voιd *ctx) { •if XVT_OS == XVT_0S_MAC QHdrPtr qhp, /* address of a QHdr structure */ DrvQEl "qep; Str255 volNa e; short vRef, rc, long avail, qhp= GetDrvQHdr( ) ,- /* address of queue header */ qep = (DrvQEl *)qhp->qHead, /* address of a queue element */ for (qep = (DrvQEl *)qhp->qHead, qep '= NULL; qep=(DrvQEl *) ep->qLιnk) { rc = GetVInfo(qep->dQDrιve, volName, tvRef, tavail), if (ire) browse_deεktop(ctx, PtoCstr(volName) ) , ) •endif } int fsys_ιterate(char "dir, int Cfunc) (), void *ctx) { DIRECTORY d. SLIST si, SLIST_ELT se; mt n = 0 ,- assert ( fsys_ιsdιr (dir) ) ; xvt_f sys_save_dιr ( ) , xvt_fsys_convert_str_to_dιr (dir , id) , xvt_fsys_set_dιr (td) , si = xvt_fsys_lιst_flies("",NULL,TRUE) , for(se = xvt_slιst_get_firs (si) , se '= NULL; εe = xvt_slιst_get_nex (si, se) ) { n++; funclctx, xvt_slιst_get(si, se, NULL)), } xvt_slιst_destroy(si) , xvt_fsyε_restore__dιr( ) , return n, ) char *fsys_buιld_name(char "dir,char "fname.char "buffer, int size) { xlocal.c Thu Mar 23 13:10:05 1995 8 int len, char dc = fsys_ιs_url (dir) ''/' :dιr_char, if ( dιr==NULL || *dιr=='N0' ) { strncpy(buffer, na e,sιze-1) , buffer[sιze-l]='NO' , } else { if ( buffer'=dιr ) { strncpy(buffer,dir,sιze-3) , buffer[sιze-3]='NO' ,- } len = strlen(buffer) ; if ( buffer[len-1] '=dc ) buffer[len++] = dc, strncpy(buffer+len, fnaune,sιze-len-1) , buffer[ειze-l]='NO' ,- ) return( buffer ) ; ) /* Given a filename in a directory, p ck the directory out of it, and */ /* create a new filename using that directory and the given nametail */ char *fsys_replace_name(char "oldname,char "fname,char "buffer, mt size) { mt len; char "dirend, char dc = fsys_ιs_url(oldname) ''/' :dιr_char, dirend = strrchr(oldname,dc) , if ( dirend == NULL ) { strncpy(buffer, fname,sιze-1) ; buffer[sιze-l]='NO' ; } else { "dirend = 'NO' ; if ( buffer'=oldname ) { strncpy(buffer, oldneune, size-3 ) ; buffer [sιze-3] = ' NO' , } len = strlen(buffer) ; *dirend = dc; buffer [len++] = dc; strncpy(buffer+len, fname, sιze-len-1 ) ; buffer [sιze-l]=' NO' ; } return! buffer ) , } char *fsys_nametail (const char *oldname) { char "pt; if ( fsys_ιs_url ( (char *)oldnaune)) pt = strrchr(oldnaune, '/') ,- /* Might be an url, or relative url */ else pt = strrchr(oldname, dιr_char) ,- if ( pt "=NULL ) return! pt+1) ; else return! (char *)oldname ), } char *fsys_nametaιl2 (const char "oldname) { char "pt, dir; if ( fsys_ιs_url ( (char *)oldnaune)) dir = ' / ' ,- xlocal.c Thu Mar 23 13:10:05 1995 9 else pt = strrchr(oldname,dir) , if ( pt ==NULL ) return! (char *)oldname ), else if ( pt[l] '='\0' ) return! pt+1 ) , else { for ( --pt , pt>=oldneune tt *pt ' =dιr , --pt ) , return ! pt+1 ) , } } int fsys_same_or_no_dιr(char "namel, char *neune2) ( char "ntl, *nt2, "str, ntl = fsys_nametaιl(namel) , nt2 = fsys_nametaιl(name2) , if I ntl==namel | | nt2==name2 ) return! 1 ) , str = strstr(naunel, " //'), if ( ntl==str+3 ) /* "http //" is not a directory, needs a slash*/ returnI 0 ) , if ( ntl-namel '= nt2-name2 ) return! 0 ) , •if XVT_OS_ISUNIX return( stmcmp(naunel,name2,ntl-namel)==0 ), •else if ( str'=NULL ) return! strncmp(namel,name2,ntl-namel)==0 ), else return( mystrncasecmp(namel,name2, tl-namel)==0 ), •endif ) int fsys_same_dιr(char "namel char *name21 { char "ntl, *nt2, ntl = fsys_nametaιl(namel1 , nt2 = fsys_nametaιl(name2) , if ( ntl-namel '= nt2-naune2 ) return( 0 ) ; •if XVT_OS_ISUNIX return! strncm (namel,name2,ntl-na_mel)==0 ), •else if ( sys_ιs_url(naunel) ) return! strncm (naunel,name2,ntl-namel)==0 ); else return( mystrncasecmp(namel,name2,ntl-namel)==0 ) •endif } int fsys_m_dιr(char "file, char *dιr) ( char *nt, char "ept, t ret, int IU, lu = fsys_ιs_url(file) , if ( iu'=fsys_ιs_url(dir) ) return( 0 ) , nt = fsys_nametaιl(file) , ept = dιr+strlen(dιr)-1, if (( *ept == dιr_char ii du ) || I *ept=='/' tt iu) ) local.c Thu Mar 23 13:10:05 1995 10 "ept = 'NO' ; ret = 0; if ( nt==file it strcmp(dir, ".")==0 ) ret = 1; else if ( nt-file-1 == strlen(dir)) if ( strncmplfile,dir,nt-file-l)==0 ) ret = 1; if ( *ept=='N0' ) "ept = iu?' /' :dir_char; returnI ret ) ,- ) int fsys_add_dir_componant(char "dir, char "component, char "space, int size) { int len; char dc = fsys_is_url(dir) ?'/' :dir_char; if ( dir!=space ) { strncpy(space, ir,size- ) ; space[size-3]='NO' ; } len = strlen(space) ; if ( len==0 | | space[len-1]!=dc ) space[len]=dc; else --len; strncpy(space+len+1,component,size-len-2) ,- space[size-1]='NO' ; /* treatment of .. is different for urls (always means up on level) and "/ /* the local file system (only means up a level if stat agrees) */ if ( fsys_is_url (dir) tt strcmp(componant, "..")==0 ) { char *pt, *upt; space[len]='NO' ; pt = strrchr(space, '/') ,- upt = strstr(space, "://") ; /* Don't eat up the host name */ if ( upt!=NULL ) upt += 3; if ( pt!=NULL ScSc pt!=space it pt>upt 1 *pt = 'NO' ; } •if XVT_OS_ISUNIX /* Beware of symbolic links */ if ( strcmp(componant,"..")==0 ) { struct stat cur, parent; char "pt; sta (space,tcur) ; space[len]=' O' ; pt = strrchr(space, '/') ,- if ( pt==NULL I I pt==space ) stat( "/" ,tparent) ; else { *pt='N0' ,- stat(space,tparent) ; "pt = '/ ' ; } space!len]='/ ' ; if ( cur.st_dev==parent.st_dev it cu .st_ino==parent.st_ino ) { if ( pt==NULL I I pt==space ) strcpy(space,"/"); else *pt='N0' ; ) ) xlocal.c Thu Mar 23 13:10:05 1995 11 •elif XVT_OS_IS_WINOS if I strcmp!componant, ".." )==0 ) { char "pt; space [len] = ' NO ' ,- pt = strrchr(space, dιr_char) ; if ( pt'=NULL tt pt'=space ) "pt = 'NO' ; } •endif return ( sιze<=strlen(dιr) +strlen(componant) +2) ; } mt fsys_get_dιr_componant (char "dir, int cnt, char "space, int size) { int found; char "end, "prev, "pt; char dc = fsyε_ιs_url (dir) '' / ' :dιr_char; end = dιr+strlen(dιr) -1; if I *end==dc ) --end; found = 0; if I fsys_is_url (dir) ) { pt = strstr (dir, "://") ; if ( pt'=NULL ) pt = strchr(pt+3 , ' / ' ) ; if ( pt==NULL ) { if ( cnt'=0 ) return 0,- goto found_ιt; } else { if ( cnt==0 ) { end = pt; goto found_. t,- ) —cnt; } else { •if XVT_OS_ISUNIX if ( cnt==0 ) ( dιr=end=" / " ; goto found_ t; } —cnt; ++dir; /* I think windows 3 ust works? ! ! ! ! */ •elif XVT_OS == XVT_OS_MAC if I cnt==0 ) { dιr="Desktop" ; end = dιr+strlen(dιr) -1; goto found_ιt, } --cnt,- •endif } while ( dιr<end ) { prev = dir; while ( "prev tt *prev!=dc ) ++prev; f ( cnt==0 ) { end = prev-1; goto found_ιt; } --cnt; xlocal . c Thu Mar 23 13 : 10: 05 1995 12 dir = prev+1; if ( dc=='/' ) while ( *dir=='/ ' ) ++dir; } return 0; found_.it: if ( end-dir+2>=size ) end = dir+size-2; strncpy(space,dir,end-dir+1) ; space[end-dir+1]='NO' ,- return 1; } •if XVT_0S == XVT_OS_MAC int mac_mkdir(char *path) { Str255 dirName; long createdDirlD; OSErr iErr; strcpy( (char *)dirName, path); CtoPstr( (char *)dirName) ; iErr = DirCreate(0,0,dirName,tcreatedDirlD) ,- return (iErr) ; } int mac_rmdir(char *path) { OSErr iErr; Str255 dirName; strcpy( (char *)dirName, path); CtoPstr( (char *)dirName) ; iErr = HDelete(0, 0,dirName) ; return (iErr) ; } •endif int fsys_mkdir(char 'name) { •if XVT_OS == XVT_OS_MAC return (mac_mkdir(name) ) ; •else return( mkdir(name,0775) ) ; •endif } int fsys_rmdir(char 'naune) { •if XVT_OS == XVT_OS_MAC return (ιt_ac_rmdir(name) ) ; •else return(rmdir(name) ) ; •endif ) char *mytmpnam(char *s) { •if XVT_OS != XVT_0S_MAC return tmpnam(s) ; •else char ' buffer[256] ; char 'name; OSErr err; short foundVRefNum; long foundDirlD; xlocal.c Thu Mar 23 13:10:05 1995 13 DIRECTORY dir; naune = tmpnaunl (char *)NULL) , err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, tfoundVRefNum, tfoundDirlD) , dir.voi = foundVRefNum; dir.dir = foundDirlD; xvt_fsys_convert_dιr_to_str(tdir, buffer, sizeof(buffer)) , strca (buffer, name); if (s) strcpy(s, buffer), return (s) ; •endif ) static char *nameιnfo(char 'name, enum fιlename_type type, t *len, int *ext ι { •if XVT_0S_IS_WIN0S enum fιlename_type localtype = fn_dos, •elif XVT_OS_ISUNIX enum fιlename_type localtype = fn_mac, •else enum fIlename_type localtype = fn_posιx, •endif *ext = -1; if ( fsys_ιs_url(name) ) localtype = fn_poειx, if ( type==fn_local ) type = localtype; else if I type>localtype ) type = localtype; if I type==fn_dos ) { *len = 8; *ext = 3; return " ' N"#%i' ()*+,-/: ;<=>?<?[] "* { | }-NN" , } else if ( type==fn_mac ) { *len = 30; / » I I I About right */ return "#*i/NN.", } else { *len = 255, return "•"t/NN "; /* Include # because it means stuff in urlε */ ) } int fsys_badname(char 'name, enum fιlenaune__type type ) { char *nt. *badchars, t len, ext, cnt, if ( pmatch("mailto: " ,name) ) return 0; /* People have all sorts of 3 unk in mail urls */ badchars = nameinfo(name,type,tlen,text) ; if ( ext==-l ) { if I strlen(fsys_nametaιl (name) )>len ) return! 1 ) ; ) else { for ( nt = fsys_nametaιl(name) , cnt=0; *nt'='N0' ii "n '=' . ' ; ++nt, ++cnt ) if ( cnt>len ) return( 1 ) ; if I *nt'='N0' ) { for I ++nt, cnt=0; *nt'='N0' it 'nt 1 -' '; ++nt, ++cnt ); if I *nt=='.' || cnt>ext ) retur ( 1 ) ; ) } for ( nt = fsys_nametaιl(name) ; *nt'='N0' , ++nt ) xlocal.c Thu Mar 23 13:10:05 1995 14 if ( *nt>='N177' || *nt<' ' ) /" No parity or control characters */ return 1; else if ( strchr(badchars, "nt) !=NULL ) return( 1 ) ; return( 0 ) ,- ) int fsys_badlinkname(char "name, enum filename_type type ) { char "pt; int ret; pt = strrchr(fsys_nametail(name) ,'#') ; if ( pt!=NULL ) "pt = 'NO'; ret = fsys_badname(name, ype) ; if ( pt!=NULL ) "pt = '#' ; return ret; ) static int fsys_nametoolong(char "naune, int len, int ext ) { char "pt; if ( ext==-l ) return! strlen(name)>len ) ,- pt = strchr(name, ' . ' 1 ; if ( pt==NULL ) return) strlen(naune)>len ) ,- return( pt-name>len) ; } static int fsys_exttoolong(cnar "name, int len, int ext ) { char *pt; if ( ext==-l ) return( 0 ) ; pt = strchr(name, ' . ') ; if ( pt==NULL ) return( 0 ) ; return( strlen(pt+1)>ext ); } /* make a good naune out of a bad one. Reasonable chars, right length */ char *fsys_makegoodname(char *nm, enum filename_type type) { char "pt, "ptl, *badchars; int len, ext, cnt; char "name; badchars = nameinfo(nm,type,tlen,text) ,- name = fsys_nametail2(nm) ; for ( pt=name, ptl=na_me; *ptl; ++ptl ) if ( *ptl>=' ' tt *ptl<'N177' ii strchr(badchars, *ptl)==NULL ) *pt++ = *ptl; *pt = 'NO'; pt =• strrchr(name, ' . ') ; /* Try removing double letters, then vowels before truncating */ if ( pt==NULL I I ext==-l ) { pt = name+strlen(name)-1; while ( pt>name it fsys_nametoolong(name,len,ext) ) { xlocal. c Thu Mar 23 13:10:05 1995 15 if ( 'pt==pt[-l] ) strcpy (pt , pt+1 ) ; --pt; } pt = name+strlen(name) -1; while ( pt>=naune it fsys_nametoolong(name, len,ext) ) { if ( *pt=='a' | | *pt=='e' | | *pt=='ι' | | *pt=='o' | | *pt=='u' | | *pt=='A' | | *pt=='E' | | *pt=='I' | | *pt=='0' | | *pt=='U' ) strcpy(pt,pt+l) ; --pt; } } else { /* Remove extra dots */ for ( --pt; pt>=name; --pt ) if ( *pt==' . ' ) strcpy(pt,pt+l) ; /* Look for double letters */ pt = name+strlen(naune) -1; while ( *pt!='. ' it fsys_exttoolong(naune, len,ext) ) { if ( *pt==pt[-l] ) strcpy(pt,pt+l) ; —pt; } pt = strrchr(name, ' . ') -1 ; while ( pt>name it fsys_nametoolong(name, len,ext) ) { if ( *pt==pt[-l] ) strcpy(pt,pt+1) ; —pt; } /* Look for vowels */ pt = name+strlen (naune ) -1; while ( *pt ' = ' . ' tt fsys_exttoolong(naune, len, ext) ) { if ( *pt=='a' | | *pt=='e' | | *pt=='i' || *pt=='o' | | *pt=='u' | | *pt=='A' | | *pt=='E' | | *pt=='I' | | *pt=='0' | | *pt=='U' ) strcpy(pt, t-1) ; — t; ) pt = strchr (naune, ' . ') -1 ; while ( pt>=name it fsys_naunetoolong(name, len, ext) ) { if ( *pt=='a' | | *pt=='e' | | *pt== ' I ' | | *pt=='o' | | *pt=='u' | | *pt=='A' | | *pt=='E' | | *pt=='I' M *pt=='0' | | *pt=='U' ) strcpy(pt,pt+l) ; --pt; } } pt = strchr (naune, ' . ' ) ; if ( pt==NULL ) { if ( strlen(name)>len ) name[len] =' N0' ; } else if ( ext==-l ) { while ( strlen(name) >len it pt>name ) { strcpy(pt-l.pt) ,- —pt; } if ( strlen(name)>len ) name[len] =' NO ' ; } else { if ( strlen(pt+l)>ext ) pt[ext+l] = 'N0' ,- if ( pt-na_me>len ) strcpy(nauoe+len,pt) ,- } return nm; } xlocal.c Thu Mar 23 13:10:05 1995 16 static t lookslikehomepage(char *url) { mt off, if ( *fsys_naunetaιlturl)=='NO' ) /* catch "http //navisoft com/" */ return 1, if I pmatch("http-//',url) ) /* catch "http //naviεoft.co "/ off = εtrlenChttp //'), else if I pmatchfftp //",url) ) off = strlenCftp.//") , else return 0, return! strchr! url+off+1 '/')==NULL ), ) char *fsys_makerealname(char "nm, char "ntbuf t size, enum fιlename_type type) { /* deal with the case of making a good name out of http //rain org/ */ /* assume that foo bar spam edu the interesting name is spam */ char "ptl, *pt2, *pt3, "end, if ( lookslikehomepageInm) ) { ptl = fsys_nametaιl2(nm) , pt3 = strrchr(ptl, ' ' ), if ( pt3'=NULL 1 *pt3='N0' pt2 = strrchr(ptl, ' ' ), if ( pt2'=NULL ) ptl = pt2+l, if ( pt3'=NULL ) *pt3=' ' if ( pt3==NULL ) { ρt3 = nm+strlen(nm) , if ( pt3[-l]=='/' | | pt3[-l]=='NN' | | pt3[-l]==' ' ) —pt3 } pt2 = ntbuf, end = pt2+sιze, while ( ptl<pt3 it pt2<end ) *pt2++ = *ptl++, if ( pt2<end-6 ) strcpy(pt2, ' html ) , fsyε_makegoodname(ntbuf,type) return(ntbuf) , } else return fsys_nametaιl(nm) , } t fsys_lookslιkedιr(char "name) { if ( fsys_ιs_url(name) ) return) name[strlen(name)-1]=='/' ), else return) name[strlen(name)-1]==dιr_char ), /* Does this work on Mac' */ } t fsyε_alιas(char "path, char "buf, int bufsiz) ( •if XVT_OS_ISUNIX memset(buf, 'NO', bufsiz) return(readlink(path, buf, bufsiz) '= -1), •else return 0, •endif ) xlocal . c Thu Mar 23 13 : 10 : 05 1995 17 int f sys_urlcmp (char "urll , char *url2 ) { •if XVT_OS_ISUNIX return strcmp ( urll , url ) ; • else if ( fsys_ιs_url(urll) ) return strcm (urll,url2) , else return strmatchturll,url2) , •endif } •if XVT_OS_IS_WINOS •define Loadlcon _LoadIcon •include <wιndows.h> char *wιn_get_absolute_name(char "name, char "result, int rsiz) { OFSTRUCT o s; char *p = ofs.szPathNaune, char *q = result; OpenFile(naune, tofs, OF_PARSE) , while(*p it q < result+rsιz-1) { *q = tolowerCp) ; q++; p++, ) *q = 'NO' , return result, ) •endif void fsys__setfilecreator(char "name, char "mimetype) { FILE_SPEC fs, char "str, "pt, xvt_fsys__str_to_fs(name,ifs) , xvt_fsys_set_ ιle_attr(ifs,XVT_FILE_ATTR_CREATORSTR, (long) "HTML" ) ; if ( pmatch!"text/" .mimetype) || pmatch!"application/postscript",mimetype) pmatch("application/x-navidoc" ,mimetype) | | pmatch!"application/x-navisty e" .mimetype) | | pmatch!"application/x-navimap".mimetype) 1 str - "TEXT" ; else if ( pmatch( "image/gif" .mimetype) ) str = "GIFf" ; else if ( pmatch!"image/Dpeg" .mimetype) ) str = "JPEG"; else if ( pmatchCimage/tiff" .mimetype) ) str = "TIFF" ; else if ( pmatch!"image/pict" ,mimetype) ) str = "PICT" ; else if ( pmatch!"video/mpeg" .mimetype) ) str = "MPEG" , else if ( pmatch!"audio/aiff".mimetype) ) str = "AIFF" ; else if ( (pt=strrchr(name, ' . ' ) ) '=NULL ii strmatch(pt, " sιt")==0 ) str = "SIT 1 " ; else xvt_fsys_set_fιle_attr(ifs,XVT_FILE_ATTR_TYPESTR, (long)str) ; } char *fsyε_mιme_from_type(char "url) { •if XVTWS == MACWS if I ' fsys_ιs_url(url) ) { xlocal.c Thu Mar 23 13:10:05 1995 18 char *type,- FILE_SPEC fs; xvt_fsys_str_to_ s(url,tfs) ; type = (char *) xvt_fsys_get_file_attr(ifs,XVT_FILE_ATTR__TYPESTR) ; if ( type==NULL ) return(NULL) ; if ( strcmpttype, "GIFf" )==0 ) return! "image/gif" ) ; else if ( strcmp(type, "JPEG")==0 || strcmpttype, "JFIF" )==0 ) return! "image/jpeg" ); else if ( strcmpltype, "TIFF")==0 ) return! "image/tiff" ) ,- else if ( strcmp(type, "MPEG")==0 ) return) "video/mpeg" ),- else if I strcmpttype, "AIFF")==0 ) return! "audio/aiff" ) ,- } •endif returnI NULL ) ,- } nadlib Sat Mar 25 09:35:54 1995 Library of Scripts Routines used ior administrative functions of the server. 19:12 . 19:04 .. 19:12 RCS 14:32 admin.tcl 18:21 archive.tcl 19:12 chores.tcl 20:53 init.tcl 18:21 mi.tcl 19:32 remit,tcl 18:21 return.tcl 19:12 tables.tcl Files included for reference: archive.tcl: script that implements automatic version history of objects init.tcl: script used to register new operations. table.tcl: script used to automatically create tables from forms. archive.tcl Sun Fab 26 18:21:41 1995 1 proc Archive {) { global NS set urlv [split SNS(url) /] set url /[ 3 oιn [lrange $urlv 4 end] /] set ts [ArchiveDecodeTS [lmdex Surlv 3]] set row [mι_0orlrow SNS(dbconn) N "select archιve_type,LOToFιle(archιve_lo, ' /tmp/nsarchive' ) from ns_archιves@N [timestamp 'S ts'N] where archιve_path='$url' ; ' ] if {$row == ""} { set file $NS(pageroot)/$url if [file exists $fιle] { ns_returnflie 200 [ns_guesssuffix Sfile] $fιle } else { ReturnPlain 500 "No such file $fιle } } else { set file [lmdex Srow 1] set type [lmdex $row 0] ns_returnflie 200 Stype Sfile ns_unlmk $fιle } } proc ArchiveVersions {} { global NS set urlv [split SNS(url) /] set url /[ 3 oιn [lrange Surlv 3 end] /] set page N "<HTMLxHEADxTITLE>Versιon Pιcker</TITLEx/HEAD> <BODYxHl>Versιons for Surl</Hl>" foreach row [mι_select_rows SNS(dbconn) N "select train- -timestamp + interval '1' second from ns_archιves@ [, N) where archive_path = '$url';"] { set tmm [lindex [split [lmdex Srow 0] ] 0] set when [ArchiveEncodeTS Stmin] append links N "<LIxA HREF=SNS(serverSelf) /NS/Archive/SwhenSurl>$tmιn</A>' } if [info exists links] { append page "Please choose a version <UL>$lιnks</UL>' } else { append page "No versions found " } append page "</BODYx/HTML>" ReturnHtml 200 Spage } proc ArchiveEncodeTS {ts) ( regsub -all -- {(- ]} Sts ■ • time return Stime } proc ArchiveDecodeTS (ts) { set date "[string range Sts 0 3]- [string range Sts 4 5]-[string range $ts 6 7]' set time "[string range Sts 8 9] : [string range $ts 10 11] [string range Sts 12 13] return "Sdate Stime' tablaa.tcl Thu Mar 23 19:12:31 1995 1 * # The maximum number of allowed columns * set NS(maxColumns) 10 * # The list of reserved words from Appendix C of the Illustra User's Manual. * set NS( eservedWords) [list N abort absolute add after aggregate alert alerter all after and N any archive arch_store arg as asc at authorization backward before N begin between binary binding bit boolean both by cascade cast char N character char_length character_length check close collate collection N column commit copy create createdb current_date current_tιme N current_tιmesta_mp current_user cursor database date desc decimal N declare delete desc distinct do double drop dump end escape exists N external extract fetch first float for forward from function grant N group having ignore in index indexable insensitive insert instead N int integer interval into is key language last leading like link N listen local micopy move next none nonulls not null numeric of N on only open operator option or order overlapε poll position N precision prior privileges public read real recover ref relative N rename restore restrict return returns revode roolback rule N schema scrool select sessιon_user set smallint some stdin stdout N store substring system_user table time timestamp to trailing N transaction trim type unary under union unique update usage user N using vacuum values varchar variant varying version view virtual N where with zone] proc 500 {msg} { ReturnPlain 500 Smsg ) proc GetNewTableForm {} { global NS # List of allowed Illustra types. foreach type [list text integer real boolean date time timestamp] { append types "<OPTION>Stype ' ) set page N "<htmlxhead><tιtle>New Table</tιtle></headxbody> <IMG SRC=N"/NS/Asset/NewTableFormHeader.gifN"><BR>Nn To create a new table you must:Nn <ul> <lι>Name the table. <lι>Provιde a short description for the table. <lι>Decιde if the table should show up on the list of searchable tables </ul> In addition, for each column in the new table (up to SNS(maxColαmns) columns are allowed), you need to: <ul> <lι>Na_me the column. <lι>Select the column type <lι>Provιde a short description of the column <lι>Optιonally, select one or more of: <ul> <li>not null: Null values are not allowed for this column. <lι>unιque: All values must be unique (also implies not null) . <li>mdex: An index should be created on this column </ul> </ul> tables.tcl Thu Mar 23 19:12:31 1995 2 When finished, press the <strong>Create Table</strong> button to create the new table. <BR>SNS(assetRule) <form action=$NS(serverSelf) /NS/CreateTable method=post> <pre> Table Name: <input name=Table size=20> Table Description: <input name=Description size=40> Table is Searchable: <input type=checkbox name=Searchable checked>" for {set n 1} {$n <= SNS(maxColumns) } {incr n} { append page N "<BR>SNS(assetRule) <b>Column $n</b>: Name: <input name=Col$n.Name size=20> Type: <select name=Col"$n.Type>$types</select> Description: <input name=Col$n.Description size=40> not null: <input type=checkbox naune=ColSn.NotNull> unique: <input type=checkbox name=Co l$n.Unique> index: <input type=checkbox naune=Col$n.Index> ) append page N "<input type=submit value=N"Create TableN"x/prex/formx/bodyx/html>" ReturnHtml 200 Spage proc CreateTable {} { global NS Form * # Sanity checks. # if ! [info exists Form(Table)] { return [500 "You must specify a table name."] } if ! [info exists Form(Coll.Name) ] { return [500 "You must specify at least one column name."] } # Initialize the word mangier. # Manglelnit # • Initallize variables to hold the SQL statements. • set ismeta f set searchable f set basetable [string trim $Form(Table)] set table [Mangle Sbasetable 0] set n 0 while { [TableExists Stable] ) { set table SbasetableSn incr n if {$n > 10} { return [500 "Too many tables starting with Sbasetable"] } ) # Hack: Forget the table name so like-named columns aren't mangled. set NS(knownWords) "" tablaa.tcl Thu Mar 23 19:12:31 1995 if [info exists Form(Searchable) ] { set searchable t } set create "create table Stable (Nn" for {set n 1} {$n <= SNS(maxColumns) } {incr n} { set name [string trim SForm(Col$n.Name) ] if {Snaune == "") { break, } set name [Mangle Sname] set type [string trim SForm(ColSn.Type) ] if {Sname == "ns_url" tt Stype == "text"} { set ismeta t if {$n > 1} {append create " , Nn"} append create ' Snaune Stype" if [info exists FormlColSn.Unique) ] { append create " not null unique" } elseif [mfo exists Form(Col$n.NotNull) ] { append create " not null" } if [info exists FormlColSn.Index) ] { append indices " create index ${table}_by_Sname on Stable using btreetSname) , Nn" ) if {SFormtColSn.Description) '= "") ( lappend cinfo " insert into ns__columns (column_table,column_naune,coluπιn_descrιptιon) values ( 'Stable' , 'Sname' , ' [ns_enquote $Form(Col$n.Description) ] ' ) , ' ) } append create "Nn);Nn" set tιnfo_cols "table__naune, table_ιssearchable, table_ιsmeta' set tmfo_vals "'Stable', 'Ssearchable' , 'Sismeta'" f (SFormtDescription) '= ""} { append tιnfo_cols " , table_descrιptιon" append tιnfo_vals ", ' [ns_enquote SForm(Descrιptιon) ] ' " ) set t fo "insert into ns_tables ($tιnfo_cols)NnNtvalues ($tιnfo_vals) if [catch { mι_dml SNS(dbconn) Screate if [info exists indices] { mι_dml SNS(dbconn) Sindices ) mι_dml SNS (dbconn) St fo if [ info exists cinfo] { # Get around alerter bug - multiple transactions, foreach info Scinfo { mi__d.nl SNS(dbconn) $mfo } } } errMsg] { return [500 "Could not create new table SerrMsg"] } set page "<htmlxhead><tιtle>New Table Created</tιtlex/head> tables.tcl Thu Mar 23 19:12:31 1995 4 <body><hl>New Table Stable Created</hl> Your new table has been created and you can now <a href=$NS(serverSelf)/NS/GetEntryForm/Stable>enter new data.</a>" # # If any names where mangled, warn the user instead of creating. # if [info exists NS(mangledWords) ] { append page N "<pxstrong>Notιce:</strong> The table and/or column names in your new table had to be altered to avoid conflicts with existing tables or reserved words. Please review the following list of altered names. If the new names are acceptable, do nothing. Otherwise, press the N'Drop Altered TableN" button to drop the altered table and try again. <dl compact>" foreach word SNS(mangledWords) { append page " <dt>$NS(mangledWordOrig.Sword)<dd>$word" } append page " </dlxform action=$NS(serverSelf) /NS/VerifyDropTable method=post> <input type=hidden name=Table value= "StableN"> <ιnput type=submit value=N"Drop Altered TableN">" } append page "</bodyχ/html>" ReturnHtml 200 Spage proc GetDropTableForm {} { global NS ReturnHtml 200 N "<htmlxhead> <title>Drop Table</tιtlex/headxbody> <IMG SRC=N"/NS/Asset/DropTable.gi \"><BR> <form action=$NS(serverSelf) /NS/VerifyDropTable method=post> Table to Drop: <ιnput name=Table sιze=20> <input type=submιt value=N"DropN"x/formx/bodyχ/ht_nl>" } proc VerifyDropTable {) { global NS Form set table [string trim SForm(Table) ] if (Stable == "") { return [500 "Please specify a table to drop."] } if ! [TableExists Stable] { return [500 "Stable does not exist."] } if [string match ns_* Stable] { return [500 "Stable is a Naviserver system table and can not be droppeds. ] } ReturnHtml 200 N "<htmlxhead> <title>Verify Drop Table</titlex/headxbody> <hl>Verify Drop of an Existing Table</hl> tablea.tcl Thu Mar 23 19:12:31 1995 5 <form actιon=$NS(serverSelf)/NS/DropTable method=post> <ιnput type=hιdden name=Table value=$table> Are you sure you want to drop the <ι>Stable</ι> table with the following SQL <pre> [dropSql Stable] </pre> <b>All present and historical data will be permanently lost'</b> <mput type=submιt value=N"Yes, Really DropN"> </for x/bodyx/html>' } proc dropSql table { return "delete from ns_columns where column_table = 'Stable' delete from ns_tables where table_name = 'Stable', drop table Stable, " } proc DropTable {} { global NS Form set table [string trim SForm(Table) ] if {Stable == ""} { return [500 "No table to drop specified."] } if ' [TableExists Stable] { return [500 "Table Stable does not exists ' ) } if [catch {mι_dml SNS(dbconn) [dropSql Stable]}] { return [500 "Could not create new table "] ) ReturnPlain 200 "Table Stable dropped " ) proc TableExists table { global NS set row [mι_0orlrow SNS(dbconn) N "select 1 from tables where table_name = 'Stable',"] if {Srow '= ""} { return 1 } else { return 0 ) } proc Manglelnit {) { global NS set NS( nownWords) "" if [info exists NS(mangledWords) ] { foreach word $NS(mangledWords) { catch {unset NS(mangledWordOrig.Sword) ) } unset NS(mangledWords1 ) proc Mangle {word {remember 1}} { global NS # Save the original word set orig Sword tablas.tcl Thu Mar 23 19:12:31 1995 # Strip punctuation and change space, tab and dash to underscore, regsub -all ( [ Λ a-zA-Z0-9_ -]} Sword "" word regsub -all { [- ]+) Sword _ word # Check for used and reserved words. set n 0 set base Sword while {1} { if {([Isearch SNS(knownWords) Sword] == -1) tt ([Isearch SNSIreservedWords) Sword] == -1)) { break; } set word SbaseSn incr n } # Remember mangled words. if {Sword != Sorig} ( lappend NS(mangledWords) Sword set NS(mangledWordOrig.Sword) Sorig } # Remember known words. if Sremember { lappend NS(knownWords) Sword } return Sword nad Sat Mar 25 09 :48 :13 1995 1 Main body of the core server and operations -r--r 1 gww -r--r 1 doug -r--r 1 gww -r--r 1 doug -r—r 1 doug -r--r 1 doug -r--r 1 gww -r--r 1 doug -r—r 1 gww -r--r 1 gww -r--r 1 doug -r--r 1 gww -r--r 1 gww -r--r 1 gww -r--r 1 gww -r--r 1 gww -r--r 1 doug -r--r 1 gww -r--r 1 gww -r--r 1 doug -r--r--r-- 1 gww -r--r 1 doug -r--r 1 gww -r--r 1 3 ιmbo -r--r 1 gww -r--r 1 gww -r--r 1 gww -r--r 1 gww -r—r 1 lori -r—r 1 gww -r--r 1 gww -r—r 1 gww -r--r 1 gww -r--r 1 gww -r--r 1 3 ιmbo -r--r 1 doug -r--r 1 gww -r--r 1 gww -r—r 1 jimbo -r--r 1 lori -r--r 1 jimbo -r--r 1 doug -r--r 1 gww -r--r 1 doug Files included for reference: Describe.c: code that attaches descriptive indexes to addresses Fastpath.c: code that executes default operations, those that are not registered with the server GetForm.c: code to implement autogeneration of forms GetHilitedPage..c: code that highlights search terms in a page MoreLikeThiε.c : code that does similarity search on pages Navlink.c: automatic generation of hyperlinks Ng2Hlmks.c- automatic generation of hyperlinks aad Sat Mar 25 09:48:13 1995 Ng2AnchorProb.c: automatic generation of hyperlinks TclOp.c: executes scripted operations, extensibility of server TypeCheck.c: verifies datatypes conform to standards for dbms hilite.c: used in highlighting search terms from queries mergepage.c: merges data from dbms into HTML forms, used on db updates nlmk.c- automatic generation of hyperlinks nsd.c: mam body of the server, place to register new C oeprations veπfys Daacrlba.c Thu Mar 23 14:22:02 1995 •include "nsd.h" static Form "tables = NULL; void GetMetaTables(Ns_Conn "conn) { NS_DSTRING ds; char "url; if (conn->form == NULL) { return Ns_ReturnBadUrl (conn) ; } url = GetFormValue(conn->form, NS_FORM_URL_KE ) ; if (url == NULL) { return Ns__ReturnBadUrl (conn) ,- ) if (tables == NULL) { ImtMetaTables ( ) ; } ns_dstrιng_mιt (ids) ; ns_dstπng_append ( ids , "<HTMLxHEADxTITLE>Metadata Table Chooser</TITLE>" " < /HEADxBODYx IMG SRC= N " /NS /Asset / " NS_ASSET_METADATA_HEADER "N"><BR>Nn* 1 ; if (tables->NumF elds == 0) { ns_dstπng_append(ids, "No meta data tables found on this server . " ) } else { mt i ; ns_dstrιng_append(tds, "Please choose a meta data table ' "to enter your URL description:<P>" ) , for d = 0; l < tables->NumFιelds; ++ι) { DM_TableInfo "tinfo; char "table, char "description; char "describeUrl; table = tables-> lelds[i] .name; if (table == NULL) { continue; } tmfo = DM_GetTableInfo(table) ,- if (tinfo == NULL) { Ns_Log(Error, "Could not get table info " "for the %s table", table); continue; } describeUrl = Bu ldDescribeURL( table, url) ,- ns_dstrmg_varappend ( ids , "<A HREF=N"", describeUrl, "N">", NULL); description = DM_TableDescrιptιon(tinfo) ; if (description != NULL) { ns_dstrmg_append(ids, description) , Daacriba.c Thu Mar 23 14:22:02 1995 2 } else { ns_dstring_varappend(ids, table, " table", NULL) } ns_dstring__append (tds , "</AxP>" ) ,- } } ns_dstr ing_append ( ids , " < / BODYx /HTML> " ) ,- Ns_ReturnHtml (conn, 200 , ds . string, ds . length) ,- ns_dstring_free (tds ) ; void InitMetaTables(void) { Form "row; if (tables != NULL) { ns_free(tables) ,- tables = NULL; ) tables = NewFormtNULL, NULL, 0) ; row = DM_Select("select table_name from ns_tableε where table_ismeta; ") if (row == NULL) { Ns_Log(Error, "Could not initialize meta table picker."); return; ) while (DM_GetRow(row) == DM_OK) { char *table; table = row-> ields[0] .value, • if (table == NULL) ( continue; } AppendFormFieldttables, table, NULL, 0, 0); } DelForm(row) ,- FastPath.c Thu Mar 23 11:53:12 1995 •include "nsd.h" •include <dιrent.h> 3 ιmbo needs to do ArchiveVersions Ns_PagePath(url,NS_DιrFιlesOK | NS_TopPagesOK) ArchiveGet Ns_PagePath(url,NS_DιrFιlesOK | NS_TopPagesOK) 3 ust for checking permissions' ArchivePut, 3 ust calls fastpath DeferPageUpdate Ns_PagePath(url,NS_TιldesOK|NS_DιrfllesOK|NS TopPagesOK) FastPathGet Ns_PagePath(ur1,NS TildesOK| ?NS_NvdsOK| S_DιrfilesOK|NS_TopPagesOK|NS_DιrsOK) FastPathBrowse Ns_PagePath(url,NS_TιldesOK|Ns_DιrsOK) FastPathDelete Ns_PagePath(url,NS_NvdsOK|NS_DιrfιlesOK) FastPathPut Ns_PagePath(url,NvdsOK|NS_DιrfllesOK| S_DιrsOK) */ static void FastGetOrHead(Ns_Conn "conn) , static mt AcceptsNvds(Ns__Conn *conn) , static void FastImageMap(Ns_Conn "conn, char *fιle) , static void NormallzeCoordinatestint *low, mt *hιgh) , static void AddDιrLιstmg(NS_DSTRING *pds, char *url, char *dιrnaune) ; static void FastRetumFile(Ns_Conn *conn, int status, char *type, char 'file). static void FastBrowse(Ns__Conn "conn) ; static void AddBrowseLιne(NS_DSTRING *pds, char *url, char *relfιle) static void FastDelete(Ns_Conn *conn) , static mt DeleteDoclchar *nvd, char *url) static mt DeleteFilelchar *fιle, char *url), static void FastPut(Ns_Conn *conn) ; static mt SaveDoc(char 'content, char *dιr, char 'docurl), static int SaveFιle(char 'content, int len, char 'file, char 'url, char 'type) static char *chop(char 'f le); static mt sread(char 'buffer, nt len, char "psrcstr) , static char *sgets(char 'buffer, int size, char "psrcstr), void Ns_FastPathOp(Ns_Conn 'conn) char 'method = conn->request->method, if (STREQ(method, "GET") | | STREQlmethod, "HEAD")) { FastGetOrHeadlconn) ; ) else if (STREQlmethod. "BROWSE")) { FastBrowse(conn) ; } else if (STREQ(method, "DELETE")) { FastDelete(conn) ; ) else if (STREQlmethod, "PUT")) { FastPut(conn) , ) else { Ns_ReturnBadRequest(conn) , FaatPath.c Thu Mar 23 11: 53 : 12 1995 2 } ) static void FastGetOrHead(Ns_Conn *conn) { char file[_POSIX_PATH_MAX] ; struct stat st; char *url ,- ur] = conn->request->url; if (Ns_PagePath(url, file, εizeof (file) -1, NULL,0, NS_TildesOK I (AcceptsNvds(conn) ? NS_NvdsOK : 0) j NS_DirfilesOK|NS_TopPagesOK|NS_DirsOK, tst) == NULL) { return Ns_ReturnNσtFound(conn) ; 5 if (conn->request->query != NULL) { /* handles GET and HEAD the same */ return FastlmageMap(conn, file) ,- } if (S_ISDIR(st.st_mode) ) { NS_DSTRING ds; nε_dstring_init (ids) ,- AddDirListing(tds, url, file) ,- Ns_HtmlHeaders(conn, 200, ds. length); Ns_LastModifiedHeader (conn, t (s .st_mtime) ) ,- Ns_EndOfHeaders (conn) ; Ns_WriteConn(conn, ds. string, ds. length); ns_dstring_free (ids) ; ) else { return FastRetumFile (conn, 200, NULL, file) ,- } } static void FastlmageMap(Ns_Conn *conn, char *file) { char *type = guess_su fix(file) ; int x, y; FILE *fp; char buf [0x100],- char *url, *ans; if (! STREQ(type, "application/x-navimap" ) ) { return Ns_ReturnError(conn, "%s is not an image map", conn->request->url) ; ) if (sscanf (conn->request->query, "%d,%d", tx, ty) != 2) { return Ns_ReturnError (conn, "%s is wrong format for" "an image map" , conn->request->query) ,- ) fp = fopen(file, "r"); if (fp == NULL) { return Ns_ReturnNotFound(conn) ; } ans = NULL; while (fgets (buf, sizeof (buf), fp) != NULL) { if ( (url = Ns_Match("rect ", buf)) != NULL) { FaatPath.c Thu Mar 23 11:53:12 1995 3 int left, top, right, bottom,- char *p = strchr (url, ' '), *p++ = 'NO' ,- sscanflp, "%d,%d %d, %d" , ileft, itop, iright, tbottom) ; NormalizeCoordinates (tleft, tπght) ; NormalizeCoordinateε(itop, tbottom) ; if (x >= left it x < right it y >= top it y < bottom) { ans = url,- break; ) ) else if ((url = Ns_Match("default ", buf)) ' = NULL) { ans = url; break; } } fclose(fp) ; if (ans != NULL) { return Ns_ReturnRedιrect(conn, Ns_AbsoluteUrl(ans) ) ; } else { return Ns_ReturnNoResponse (conn! ; ) static void NormalizeCoordinates (int 'low, mt 'high) { if Clow > 'high) { *low = *hιgh; *high = tmp; } } static void FastBrowse (Ns_Conn *conn) { char *url,- char fιle[_POSIX_PATH_MAX] , struct stat st; DIR *dιr; struct dirent 'dent; NS_DSTRING ds; List *f les,*m; url = conn->request->url; if (Ns_PagePath(url, file, sizeof (file) - , NULL, 0, NS_TlldesOK| S_DιrsOK, ist) == NULL) { return Ns_ReturnNotFound(conn) ; ) if ( l S_ISDIR(st.st_mode) ) ( return Ns_ReturnForbιdden(conn) ; } dir = opendir (file) ; if (dir == NULL) { return Ns_ReturnForb dden(conn) ; ) FaatPath.c Thu Mar 23 11:53:12 1995 4 files = NULL; while ((dent = readdir(dir) ) '= NULL) { files = cons(ns_strdup(dent->d_name) , files) ; } closedir(dir) ; fileε = Sort(files,strcmp) ; ns_dstrιng_ιnι (ids) , for(m=files;m'=NULL;m=m->rest) { AddBrowseLine tids , url , m->fιrst ) , ) FreeList ( files , ns_f ree) , Ns_ContentHeaders ( conn, 200 , "applιcatιon/x-navιbrowse' , ds . length) Ns_WπteConn ( conn, ds string, ds . length) , static void AddBrowseLιne(NS_DSTRING *pdε, char 'dirurl, char 'relfilel { char fulifile[_POSIX_PATH_MAX] , char url [_POSIX_PATH_MAX] , char *type, εtruct stat st, if (Ns_MakePath(url,sizeof(url)-l,dirurl, relfile, NULL) == NULL) { return, } if (STREQ(url, "/ ")) { return, . if (Ns_PagePath(url,fulifile,sizeof(fulifile) -1, NULL, 0, NS_TιldesOK | NS_DιrsOK, tst) == NULL) { return, } if (S_ISDIR(st.εt_mode) ) { char *nvd nvd = Ns_NvdFιlePathturl,NULL,0) , if (nvd it sta (nvd, ist) == 0) { type = "application/x-navidoc" ; ) else { type = "application/x-navidir" ,- } } else { type = guess_suffix(fulifile) , } ns_dstrmg_varappend (pds , type, " " , relfile, " Nn " , NULL) , } static void FastDelete(Ns_Conn *conn) { char *url; char fιle[_POSIX_PATH_MAX] , char normurl [_POSIX_PATH_MAX] , char *type, struct stat st; FaatPath.c Thu Mar 23 11:53:121995 5 url = conn->request->url; if (Ns_PagePath(url,file,sizeof(f le)-1, normurl,sizeof(normurl)-1 (AcceptsNvds(conn) ? NS_NvdsOK : 0) I NS_DirfilesOK, ist) == NULL) { return Ns_ReturnBadRequest(conn) ; } type = guess_suffιx(file) ; if (STREQltype, "application/x-navidoc") ) { if (DeleteDoc(flie, normurl) == NS_OK) { return Ns_ReturnOk(conn) ; } else { return Ns_ReturnError(conn, "Cannot delete MmiWeb"),- } } if (DeleteFile(file, normurl) == NS_OK) { return Ns_ReturnOk(conn) ,- ) else { return Ns_ReturnError(conn, "Cannot delete file"); ) static int DeleteDoc(char *nvd, char *docurl) FILE 'fp; char buf[0x100] , char "dir; int state; fp = fopenfnvd, "r"),- if (fp == NULL) ( return NS_FAIL; } state = 0; /* haven't found pages yet dir = chop(nvd) ; while (fgetstbuf, sizeof(buf), fp) != NULL) { if (state == 0) { if (Ns_Match("pages: ", buf) != NULL) { state = 1; } ) else { char "pos ; char f ile [_POSIX_PATH_MAX] ; char f ileurl [__POSIX_PATH_MAX] ,- mt status ; if ( ("buf == '" ' ) ii ((pos = strchr(buf + 1, '"')) '= NULL)) { "pos = 'NO' ; if (Ns_MakePath(fιle,sizeof(file)-l,dir, uf+1,NULL) == NULL) fail: fclose(fp) ,- return NS_FAIL; } if (Ns_MakePath(fileurl,sizeof(fileurl)-1,docurl,buf+1, ULL) FaatPath.c Thu Mar 23 11:53:12 1995 6 == NULL) { goto fail; } status = DeleteFiletfile, fileurl); if (status == NS_FAIL) { goto fail; ) ) else { goto done; } } ) done: fclose(fp) ,- if (unlink(nvd) != 0) { return NS..FAIL; } r dir(dir) ; return NS_0K; } static int DeleteFile(char "file, char *url) { char "type; if (unlink(file) != 0) { return NS_FAIL; } type = guess_suffix(file) ; if (STREQ(type, "text/html") ) { DeferPageDelete(url) ,- } return NS_OK; } static void FastPut(Ns_Conn "conn) { char "url; char file[_POSIX_PATH_MAX] ; char normurl [_POSIX_PATH_MAX] ; char *content; int contentlen; Ns__Set "headers; char *type; int exists, create; struct stat st; url = conn->request->url; content = conn->content; if (content == NULL) { return Ns_ReturnBadRequeεt(conn) ,- ) contentlen = conn->contentLength; headerε = conn->headerε; if (headers != NULL) { create = (Ns_SetGe (headers, "X-NAV CREATE" ) != NULL) type = Ns_SetGet(headers, "CONTENT-TYPE"); } else { create = 0; type = NULL; FaatPath.c Thu Mar 23 11:53:12 1995 7 } if (type == NULL) { type = guess_suffιx(url) ; } if (Nε_PagePath(url, file,sizeof(file) -1, normurl,sizeof(normurl)-1, NS_NvdεOK|NS_DirfιleεOK|NS_DιrsOK, ist) '= NULL) { exists = 1; } else { exists = 0; } if (create it exists) { return Ns_ReturnError(conn, "%s already exists", url); } if (STREQ(type, "application/x-naviwad" ) ) { if (exists) { if (S_ISDIR(st.st_mode) ) { char nvd[_POSIX_PATH_MAX] ; struct stat nvdst; if (Ns_NvdFιlePath(url,nvd,sizeof(nvd)-1) '= NULL) { if (stat(nvd, tnvdst) '= 01 ( return Ns_ReturnError(conn, "Cannot save MiniWeb to " "existing non-MiniWeb directory"), } } } else { return Ns_ReturnError(conn, "Cannot save MiniWeb " "to existing file"); } } else { if (mkdιr(file, S_IRWXU) '= 0) { return Ns_ReturnError(conn, "Cannot not create " "directory for MmiWeb"); } } if (SaveDocicontent, file, url) == NS_OK) { return Ns_ReturnOk(conn) ; ) else { return Ns_ReturnError(conn, "Cannot save MiniWeb" ) ; ) } if (SaveFile(content, contentlen, file, normurl, type) == NS_OK) { return Ns_ReturnOk(conn) ; } else { return Ns_ReturnError(conn, "Cannot save file"); } } /* assumes that the directory exists */ static int SaveDocfchar "content, char "dir, char "docurl) { char buffer[2048] ; asεert(content '= NULL); FaatPath.c Thu Mar 23 11:53:12 1995 8 asεertldir ■ = NULL) ; while (sgets (buffer, sizeof (buffer) , tcontent) '= NULL) { if ("buffer '= 'NO') { char *m; if ( (m = Ns_Match("Content-Name: ", buffer)) '= NULL) { name = ns_strdup (m) ,- } else if ( ( = Ns_Match( "Content-Type ", buffer)) '= NULL) { type = ns_strdup(m) ; } else if ( ( = Ns__Match( "Content-Length ", buffer)) '= NULL) { if ((name == NULL) | | (type == NULL) | | (size == -1)) { ns_free(name) ; ns_free(type) ,- return NS_FAIL, char fileurl [_POSIX_PATH_MAX] , mt fd, mt wrote, file = Ns_MakePath(NULL,0,dιr, name, NULL); if (file == NULL) { goto die; } fd = open(file, 0_WRONLY | 0_CREAT | O TRUNC, RUSR I S_IWUSR) , wrote = wπtetfd, content, size); close(fd) ; if (wrote '= size) { goto die; ) if (Ns_MakePath(fileurl, sizeof (fileurl) -1 ,docurl , name, NULL) == NULL) { goto die, } DeferPageUpdate (fileurl, type), ns_free(type) ,- nε_free(naune) ; content += size; type = NULL; name = NULL; size = -1; } } ) return NS_OK; ) static int SaveFιle(char "content, mt len, char 'file, char "url, char "type) { int fd; mt wrote; FaatPath.c Thu Mar 23 11:53:12 1995 9 assert(content != NULL); assert{type != NULL); assert(file != NULL) ; assert(url != NULL); fd = open(file, 0_WRONLY | 0_CREAT | 0_TRUNC, S_IRUSR | S_IWUSR) ; • if (fd < 0) { return NS_FAIL;. } wrote = write(fd, content, len); close(fd) ; if (wrote != len) { return NS_FAIL; ) DeferPageUpdate(url, type) ; return NS_OK; static int AcceptsNvds(Ns__Conn "conn) { char "useragent; if (conn->headers != NULL) { useragent = Ns_SetGet(conn->headers, "USER-AGENT" ) return ((useragent != NULL) tt Ns_Match("StrandLib" , useragent) ) ; } return 0; /* * Only things different from Ns_ReturnFile is the X-Navidoc header, and that * it pays attention to the conn->requeεt->method. */ static void FastRetumFile(Ns_Conn "conn, int status, char "type, char "file) { char *docpath,- docpath = NULL; if (AcceptsNvds(conn) ) { char "path; struct stat st; path = chop(conn->request->url) ; path = Ns_NvdFilePath(path,NULL,0) ,- if (path tt (stat(path, tst) == 0)) { path = chop(conn->request->url) ; docpath = Ns_AbsoluteUrl(path) ; } } Ns_ReturnFileWithDocHeader(conn, status, type, file, docpath); /* * Takes the tail off the filename */ static char * FaatPath. c Thu Bar 23 11 : 53 : 12 1995 10 chop (char " file) { static char firstpart[_POSIX_PATH_MAX] , char "point, asserttfile '= NULL), strcpy(firstpart, file), if ((point = strrchr(firstpart, '/')) '= NULL) { 'point = 'NO' , ) return firstpart, static void AddDιrLιstιng(NS_DSTRING *pds, char *url, char "dirname) { DIR "dir, struct dirent "dent, List *fιleε,*m, dir = opendir(dirname) , if (dir == NULL) { return , ) ns_dstr mg_varappend (pds , " <HTMLxHEADxTITLE> Nn "Directory listing of " , url, "</TITLE>" "<BASE HREF=N"", Ns_AbsoluteUrl (url) , "/lιεtιngN"x/HEAD><BODY>Nn' , "<Hl>Dιrectory listing of '", url, "'</HlxHR>", NULL) , files = NULL, while ((dent = readdir(dir) ) = NULL) { files = cons(ns_εtrdup(dent->d_name) ,files) } closedir(dir) ; files = Sor (files,strcmp) , for<m=flies;m'=NULL;m=m->rest) { nε_dstπng_varappend(pds, "<A HREF=N"", m->fιrst, "N">" m->fιrst, "</A><BR>Nn' , NULL), ) FreeList(files,ns_free) ; ns_dstrmg_append(pds, "</BODYx/HTML>") ; static char * sgets(char "buffer, int size, char ""psrcstr) { char "pos = buffer, if ("psrcstr == 'NO' ) { return NULL, } while ("psrcstr '= 'NO') { if (("psrcstr == 'Nn') || ("psrcstr == 'Nr')) { (*psrcstr)++, if (("psrcstr == 'Nn') || ("psrcstr == 'Nr')) { FaatPath.c Tbu Mar 23 11:53:12 1995 11 ( 'psrcstr) ++ ,- ) break ; } else { *pos = "psrcstr; pos++; ("psrcstr ) ++; ) } "pos = 'NO'.- return buffer; static mt sread(char "buffer, int len, char *"psrcstr) { char "pos = buffer; int toread = len; while (toread > 0) { if ("psrcstr == ' NO' ) { return -1; } "pos = *"psrcstr; pos++; (*psrcstr)++; toread—,- } "pos = 'NO'.- return len; GetForm.c Sat Mar 18 21:36:16 1995 1 •include "nsd.h" static char rcsιd[] = "Sid. GetForm c,v 1.33 1995/03/19 05:36.18 doug Exp $",- •define ENTRY 0 •define UPDATE 1 •define SEARCH 2 static Ns_HashTable entryForms, static Ns_HashTable searchForms; εtatic initialized = 0, static mt IsCacheable(char "table), static void DestroyCache(Ns_HashTable *pht), static char *FιndHashedForm(Ns_HashTable *pht, char 'dbtable) , static void HashForm(Ns_HashTable "pht, char "dbtable, char "form), static char 'BuildEntryFormfchar 'dbtable, Ns_Set 'hidden), static char *BuιldSearchForm(char 'dbtable) , static void AddTableHeader(DM__TableInfo 'tinfo, NS_DSTRING *pds, char "trimtext, char *ιmg) , static void AddEntryInputs(DM_TableInfo *tιnfo, NS_DSTRING *dε, Ns_Set 'hidden) , static void Addlnpu (DM_TableInfo *tιnfo, NS_DΞTRING *pds, char "name, int formtype), static void AddSelectSQLInput(DM_TableInfo "tmfo, NS_DSTRING "pds, char "name, char *htmltag_type, char *htmltag_data, int formtype) ; static void AddSelectInput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "name, char *htmltag_type, char *htmltag_data, int formtype) ; static void AddInputInput(DM_TableInfo "tmfo, NS_DSTRING "pds char "name, char *htmltag_type, char *htmltag_data int formtype) ; εtatic void AddTextAreaInput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "name, char *htmltag_type, char *htmltag_data, int formtype) ; εtatic void AddRadιoInput(DM_TableInfo "tinfo, NS_DSTRING "pdε, char "name, char *htmltag_type, char *htmltag_data, int formtype) ; static void AddAutoIncrInput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "name, char 'htmltag_type, char *htmltag_data, int formtype) ; static void AddDefaultInput(DM_TableInfo 'tinfo, NS_DSTRING *pds, char "name, int index, mt formtype) , static void AddOpSelect(DM_TableInfo "tinfo, int index, NS_DSTRING *ds) ; static void AddOrderBys(DM_TableInfo "tmfo, NS_DSTRING *ds) ; εtatic void AddSearchFieldε(DM_TableInfo "tinfo, NS_DSTRING *dε) , static void AddCollectιonFιelds(DM_TableInfo "tinfo, NS_DSTRING "ds); static char ""GetOps(char "type) ; static mt FmdMax(DM_TableInfo "tinfo); static void AddColNullInput(NS_DSTRING "pdε, char "name, int formtype); OatForm.c Sat Mar 18 21:36:16 1995 2 static void AddTimelnput(NS_DSTRING "pds, char "name), static void AddDatelnput(NS_DSTRING "pdε, char "name), static void AddColValueRadιoButton(NS_DSTRING "pds, char 'fieldname, char 'value, char 'label, int checked), static char 'PadLef (char "name, int max), static char 'PadRight(char 'name, int max) ; static char *ReadItem(char "psrcstr, char "itembuf, int maxite len) static mt formsLocked = 0, void Ns_InιtForms(void) { if (formsLocked) { return; ) if (initialized) { DestroyCache(tentryForms) , DestroyCache(tsearchForms) , } Ns_InιtHashTable(tentryForms, NS_STRING_KEYS) , Ns_InιtHashTable(tsearchForms, NS_STRING_KEYS) ; initialized = 1, char * Ns_GetSearchForm(char "dbtable) { char "form; asser ( dbtable ' = NULL) , formsLocked = 1 ; form = F dHashedForm l tsearchForms dbtable ) ; if ( form == NULL) ( form = BuildSearchFor (dbtable) , if (form '= NULL) { if (IsCacheableldbtable) ) { HashFor (tsearchForms, dbtable, form) ) ) } formsLocked = 0; return form, char * Ns_GetEntryForm(char "dbtable, Ns_Set "hidden) { char "form; assert(dbtable '= NULL) ; formsLocked = 1; if (hidden '= NULL) { form = BuildEntryFormldbtable, hidden) , ) else { form = FmdHashedFormltentryForms, dbtable), if (form == NULL) { OatForm.c Sat Mar 18 21:36:16 1995 3 form = BuιldEntryForm(dbtable, hidden), if (form '= NULL) { if (IsCacheable(dbtable) ) { HashFormttentryForms, dbtable, form), ) ) formsLocked = 0, return form; char * Ns_GetUpdateForm(char "dbtable, char "rowid, Ns_Set "hidden) { NS_DSTRING ds; DM_TableInfo "tinfo; char "url, assert (dbtable '= NULL); assert(rowιd '= NULL) ; tmfo = DM_GetTableInfo (dbtable) ,- if (tinfo == NULL) { return NULL; } formsLocked = 1, ns_dstrιng_ιnιt (ids) ; url = BuildURL(NS_OP_UpdateRow, dbtable), ns_dstrιng_varappend(ids , "<HTML>Nn" "<HEAD>Nn" "<TITLE>Update Form for Table " , dbtable, "</TITLE>" "</HEAD>Nn" "<BODY>Nn", NULL); AddTableHeader (tmfo, ids, "Update Table" , NS_ASSET_UPDATE_FORM_HEADER) ; ns_dstrιng_varappend(ids, "To update this data m the database, press the N'UpdateN" " "button after modifying any of the values in the fields below. "If you would like to forget your edits and start over with " "the existing values in the database, press the N'ResetN" button. "If you would like to 3 ust delete this data from the database, " "press the N'DeleteN" button.<P>Nn" NS_RULE, "Nn" "<FORM METHOD=N"POS N" ACTION=N"", url, "N">Nn" "<FRExB>Nn", NULL) ; AddEntryInputs (tinfo, ids, hidden); ns_dstrmg_varappend(ids, "Nn" "<INPUT TYPE=N"resetN" VALUE=N"Reset FιeldsN"> " "<INPUT TYPE=N"submitN" VALUE=N"Update DataN">" "<INPUT TYPE=N"hiddenN" NAME=N"" , NS_FORM_QINFO_KEY, NS_FORM_SEPARATOR , NS_FORM_ROWID_KEY , " N " VALUE=N " " , rowid , " N " > Nn" " < /B>< /PREx/FORM> Nn" , NULL) ; OatFoxm.c Sat Mar 18 21:36:16 1995 4 url = BuildURL(NS_OP_DeleteRow, dbtable) ; ns_dstring_varappend (ids , "<FORM METHOD=N"POST " ACTI0N=N"", url, "N">Nn" "<INPUT TYPE=N " hidden \" NAME=N"", NS_F0RM_QINF0_KEY , NS_FORM_SEPARATOR, NS_FORM_ROWID_KEY , "N" VALUE=N"", rowid, "N">" "<INPUT TYPE=N"submitN" VALUE=N"DeleteN">" "</FORM>Nn", NS_RULE, "Nn" "</BODY>Nn" "</HTML>", NULL); formsLocked = 0; return ns_dstring_movestring(ids) ; static void DestroyCache(Ns_HashTable "pht) { Ns_HashEntry "he; Ns_HashSearch hs; assert(pht != NULL); he = Ns_FirstHashEntry(pht, ths) ,- while (he != NULL) { ns_free(Ns_GetHashValue(he) ) ; he = Ns_NextHashEntry(ths) ; ) Ns_DeleteHashTable(pht) ; static char * FindHashedForm(Ns_HashTable "pht, char "dbtable) ! Ns_HashEntry "he; assert(pht != NULL); assert(dbtable != NULL); he = Nε_FindHashEntry(pht, dbtable) ; if (he != NULL) { return Ns_GetHashValue(he) ; } else { return NULL; static void HashForm(Nε_HashTable *pht, char 'dbtable, char 'form) { Ns_HashEntry 'he; int new; he = Ns_CreateHashEntry(pht, dbtable, tnew) ,- assert(new) ; Ns_SetHashValue(he, form); OatFox .c Sat Mar 18 21:36:16 1995 static char * BuildEntryForm(char "dbtable, Ns__Set "hidden) { DM_TableInfo "tinfo; NS_DSTRING ds; char *url; assert(dbtable != NULL); tinfo = DM__GetTableInfo(dbtable) ,- if (tinfo == NULL) { return NULL; ) ns_dstring_init(ids) ; url = BuildURL(NS_OP_InsertRow, dbtable); ns_dstring_varappend(ids, "<HTML>Nn" "<HEAD>Nn" "<TITLE>Entry Form for Table: ", dbtable, "</TITLE>" "</HEAD>Nn" "<BODY>Nn", NULL) ; AddTableHeader(tinfo, ids, "Enter Data for Table", NS_ASSET_ENTRY_FORM_HEADER) ns_dstring_varappend(ids, "When done filling in the fields below, " "press the N"EnterN" button to insert your data " "into the database.<P>Nn", NS_RULE, "Nn" "<FORM METH0D=N"P0STN" ACTI0N=N"", url, "N">Nn" "<PRExB>", NULL); AddEntrylnputs(tinfo, ids, hidden); ns_dstring_varappend(ids, "<INPUT TYPE=N"submitN" VALUE=N"Enter DataN"> " "<INPUT TYPE=N"resetN" VALUE=N"Clear AllN">Nn" "</Bx/PRE>Nn" "</FORM>Nn" NS_RULE, "Nn" *</BODY>Nn" "</HTML>". NULL); return ns_dstring_movestring(tds) ; static char * BuildSearchForm(char 'dbtable) { NS_DSTRING ds; DM_TableInfo "tinfo; char "url; char "max; assert(dbtable != NULL); tinfo = DM_GetTableInfo(dbtable) ; if (tinfo == NULL) { QatFozs.c Sat Mar 18 21:36:16 1995 6 return NULL; ) url = BuιldURL(NS_OP_SearchQBF, dbtable), ns_dstnng_ιnιt (ids) ; ns_dstrιng_varappend I ids , "<HTML>Nn" • <HEAD>Nn" "<TITLE>Search Form for Table- ", dbtable, "</TITLE>" "</HEAD>Nn" "<B0DY>Nn", NULL) ; AddTableHeader (tmfo, ids, "Search Table" , NS_ASSET_SEARCH_FORM_HEADER) , ns_dstnng_varappend(idε, "<A HREF=/NS/Asset/ " , NS_ASSET_SEARCH_FORM_HELP , "Help'</AxBR>Nn", NS_RULE, "<BR>Nn" "<FORM METHOD=N"POST " ACTION=N"", url, "N">Nn' "Select : Nn<PRExB>Nn" , NULL), AddSearchFields (tmfo, tdε) , AddCollectionFields (tinfo, ids) ,- ns_dstπng_append(tds , "</Bx/PRE>" ) , AddOrderBys(tinfo, ids), max = Ns_GetConfιgValue( "MaxToReturn" ) , if (max == NULL) { max = "20"; } ns_dstrmg_varappend(ids, "<BR><INPUT TYPE=N"checkbo N" NAME=N"", NS_FORM_QINFO_KEY, NS_FORM_SEPARATOR, NS_FORM_DISTINCT_KEY, "N"> Eliminate duplicate rows.<BR>" "Maximum number of records to return" , "<INPUT VALUE=" , max, " NAME-N"", NS__FORM_PREF_KEY, NS_FORM_SEPARATOR, "MaxToReturnN" SIZE=5>", NULL) ; ns_dstring_varappend(ids, "<INPUT TYPE=N"εubmιtN" VALUE=N' SearchN"> "<INPUT TYPE=N"reεet\" VALUE=N"Clear A11N"> " "</FORM>Nn" NS_RULE, "Nn" "</BODY>Nn" "</HTML>", NULL) ; return ns_dstrmg_movestrmg(ids) ; static void AddTableHeaderIDM_TableInfo "tinfo, NS_DSTRING "pds, char "trimtext, char *ιmg) { char "description; assertttinfo '= NULL) ; assert(pds '= NULL) ,- ns_dstrιng_varappend(pds, "<IMG SRC=N"/NS/Asset/" , img, "N">Nn", "<H3>", trimtext, " ", DM_TableName(tinfo) , NULL); description = DM_TableDescrιptιon(tinfo) ,- if (description '= NULL) { OatFoxm.c Sat Mar 18 21:36:16 1995 7 ns_dstrιng_var appen (pds, " (' , description, ")", NULL), } ns_dstrιng_append(pds, "</H3>Nn") , } static void AddEntryInputs(DM_TableInfo "tmfo, NS_DSTRING "ds, Ns_Set "hidden) { mt i, mt max = FιndMax(tmfo) , assert (tmfo '= NULL), assert (ds '= NULL) , name = DM__ColumnNaune(tinfo, I) , if (name == NULL) { continue, } lsvirtual = DM_ColumnValue(tιnfo, l, "column_xsvιrtual") ; if (lsvirtual '= NULL tt "lsvirtual == 't') { continue; } ishidden = 0; if (hidden '= NULL) { value = Ns_SetGet(hidden, name), if (value '= NULL) { ishidden = 1, ) } if (ishidden) { ns_dstnng_varappend(ds, "<INPUT NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARAT0R , name, "N' ' " TYPE=N" hidden N" VALUE=N"' , value, "N'>' , NULL) , ns_dεtrιng_varappend(dε, PadRigh (naune, ax) , " value, "Nn" ,NULL) , } else { ns_dstrιng_varappend(ds, PadRight (name, max), " ", NULL), Addlnput (t fo, ds, name, ENTRY), if ( (DM_TableValue(tmfo, "table_ιsmeta" ) '= NULL) ii strcmp(DM_TableValue(tmfo, "table_ιsmeta" ) , "t") == 0) { ns_ds trmg_var append (ds , "Nn" "<INPUT TYPE=N"checkboxN" NAME=N"", NS_FORM_EINFO_KEY, NS_FORM_SEPARATOR, NS_FORM_IFT_KEY, "N" CHECKED> Index text of page.Nn", NULL) , /* * Set SIZE and MAXLENGTH based on column_bound if type is char, varchar, or * character Set SIZE and MAXLENGTH to 1 if type is charl Set SIZE to 10 * if type is integer, inti, decimal or double precision. Write out two OatFox .c Sat Mar 18 21:36:16 1995 8 * radio buttons if type is boolean */ static void Addlnput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "naune, int formtype) { int index = DM_ColumnIndex(tinfo, name), char *htmltag_type, *htmltag_data; char "description; if (index < 0) { Ns_Log ( Error , "Never heard of column %ε n table %s " , naune , DM_TableName ( tmfo ) ) ; return ; } htmltag_type = DM_ColumnValue(tιnfo, index, "column_htmltag_type" ) , htmltag_data = DM_ColumnValue(tιnfo, index, "column_htmltag_data" ) , description = DM_ColumnValue( info, index, "column_descrιptιon" ) , if (htmltag_type == NULL) { AddDefaultlnput(tinfo, pds, name, index, formtype); } else { if (htmltag_data == NULL) { htmltag_data = ■ " ; } if (STREQ(htmltag_type, NS_HTMLTAG_TYPE_SELECTSQL) ) { AddSelectSQLInput(tmfo, pds, name, htmltag_type, htmltag_data, formtype), ) else if (STREQ{htmltag_type, NS_HTMLTAG_TYPE_SELECTSQLORNULL) ) { AddSelectSQLInput(tinfo, pds, naune, htmltag_type, htmltag__data, formtype), } else if (STREQ(htmltag_type, NS_HTMLTAG_TYPE_SELECT) ) { AddSelectlnput(tinfo, pds, name, htmltag_type, html ag__data, formtype) ,- ) else if (STREQ(htmltag_ ype. NS_HTMLTAG_TYPE_SELECTORNULL) ) { AddSelectlnput(tinfo, pds, name, htmltag_type, htmltag_data, formtype); } else if (STREQ(htmltag_type, NS__HTMLTAG_TYPE_RADIO) ) { AddRadιoInput(tinfo, pds, name, htmltag_type, htmltag_data, formtype), } else if (STREQ(htmltag_type, NS_HTMLTAG_TYPE_RADIOORNULL) ) { AddRadioInput(tinfo, pds, naune, htmltag_ ype, htmltag_data, formtype), } else if (STREQ(htmltag_ ype, NS_HTMLTAG_TYPE_TEXTAREA) ) { AddTextArealnput(tmfo, pds, naune, htmltag_type, htmltag_data, formtype), } else if !STREQ!htmltag_type, NS_HTMLTAG_TYPE_INPUT) ) { Addlnputlnput(tmfo, pds, naune, htn.ltag_.type, htmltag__data, formtype); } else if (STREQ(htmltag_type, NS_HTMLTAG_TYPE_AUTOINCR) ) ( AddAutoIncrlnput(tmfo, pds, name, htmltag_type, html ag_data, formtype) ; } else { Ns_Log(Error, "Never heard of htmltag_type %s" " for column %s m table %s", htmltag_type, name, DM_TableName(tinfo) ) ; AddDefaultlnput(tmfo, pds, name, index, formtype); } ) if (description '= NULL) { ns_dstnng_varappend(pds, " (" .description, " ) Nn" ,NULL) ; } ) static void AddSelectSQLInput(DM_TableInfo "t fo, NS_DSTRING "pds, char "name, char *html ag_type, char *htmltag_data, int formtype) { Form "row; int first = 1; OatFoπn.c Sat Mar 18 21:36:16 1995 9 if I (row = DM_Select(htmltag_data) ) == NULL) { Ns_Log(Error, "Query N"%sN" m htmltag_data for column %ε in table %s" " did not execute correctly" , htmltag_data, naune, DM_TableName(tmfo) ) , ns_dstrιng_append(pds, "Nn" ) ; return, ) if (Ns_SetSιze(row) '= 1) { Ns__Log(Error, "Query N"%sN" in htmltag_data for column %s in table %ε" " did not return exactly one column of data", htmltag_data, name, DM_TableName(tmfo) ) , ns_dstrιng_append(pds, "Nn" ) ; return; } ns_dstπng_varappend(pds, "<SELECT NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, "N">Nn" , NULL) ; if (STREQ(htmltag_type, NS_HTMLTAG_TYPE_SELECTSQLORNULL) || (formtype == SEARCH)) { ns_dstrιng_appeήd(pds, "<OPTION SELECTED> n") , first = 0, ) while (DM_GetRow(row) == DM_OK) { ns_dstrmg_append(pds, "<OPTION" ) , if (first) { ns_dstnπg_append(pds, " SELECTED"); firεt = 0, } ns_dstrιng_varappend(pds, "> ", Ns__SetValue (row, 0) , " Nn" , NULL), } ns_dstπng_append(pds, "</SELECT>Nn" ) , ) static void AddAutoIncrlnput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "name, char *htmltag__type, char *htmltag_data, t formtype) { Ns_Set "row; int nrows, n, char nstr[32] , NS_DSTRING sql; if (formtype '= ENTRY) { ns_dstnng_varappend(pds, "<INPUT NAME=N"", NS_FORM_VALUE_KEY , NS_FORM_SEPARATOR, name, " " "SIZE = 6>Nn",NULL) ; return; } ns_dstrιng_ιnιt (tsql) ; ns_dstrιng_varappend(tsql, "select max( " ,name, " ) from ", DM_TableName(tmfo) , " ,- " ,NULL) , row = DM_ZeroOrOneRow ( sql . string , tnrows ) ; if (row == NULL) { Ns__Log(Error, "Autolncr Could not get the max %s in %s", name,DM_TableName(t fo) ) , ns_dstnng_append(pds, "Nn") , return; ) OatFoxm.c Sat Mar 18 21:36:16 1995 10 if (nrows == 0) { n = 1; } else { char "val = Ns_SetValue(row,0) ; if (val == NULL) { n = 1; } else { n = atoi(Ns_SetValue(row,0) ) + 1,- } } sprintf(nstr, "%d" ,n) , ns_ds tr mg_varappend ( ds , " < INPUT NAME= N " " , NS_FORM_VALUE_KEY , NS_FORM_SEPARATOR , name , " N " " , " VALUE=N"",nstr, "N"" , " SIZE=6>Nn",NULL) ; } static void AddSelectlnput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "naune, char *htmltag_type, char *htmltag_data, int formtype) { char tokbuf[1024] ; t first = 1,- ns__dstnng_varappend (pds , "< SELECT NAME=N"' , NS_FORM_VALUE_KEY , NS_FORM_SEPARATOR, name, "N">Nn", NULL) ; if { STREQ ( html tag_type, NS_HTMLTAG_TYPE_SELECTORNULL ) | | (formtype == SEARCH)) { ns__dstrιng_append(pds, "<OPTION SELECTED>Nn" ) , first = 0, } while (Readltem(thtmltag_data, tokbuf, sizeofI okbuf) ) '= NULL) { ns_dstrιng_append(pds, "<OPTION") ; if (first) { ns_dstrmg_append(pds, " SELECTED"), first = 0; ) ns_dstrmg_varappend(pds, "> ", tokbuf, "Nn", NULL), } ns_dstrιng_append(pds, "</SELECT>Nn" ) , } static void AddRadioInput(DM_TableInfo "tinfo, NS_DSTRING "pds, char "name, char *htmltag_type, char *htmltag_data, t formtype) { char tokbuf[1024] , int first = 1; lf (((formtype == ENTRY) || (formtype == UPDATE)) tt STREQ(htmltag_type, NS_HTMLTAG_TYPE_RADIOORNULL) ) { AddColValueRadιoButton(pds, name, "", "Unknown", first) ; first = 0; } else if (formtype == SEARCH) { AddColValueRadioButtonlpds, name, "' , "Any", first); first = 0; } while (Readltem(ihtmltag_data, tokbαf, sizeof(tokbuf) ) '= NULL) { OatFoXB.c Sat Mar 18 21:36:16 1995 11 AddColValueRadioButtonfpds, name, tokbuf, tokbuf, first), if (first) { first = 0; } ) ns_dstrιng_append(pds, "Nn") ; } static void AddColValueRadιoButton(NS_DSTRING *pds, char 'fieldname, char "value, char "label, int checked) { ns_dstnng_varappend(pds, "<INPUT " "NAME=N" ", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, fieldnaune, "N" "TYPE=N"radio " " "VALUE=N"", value, " " " , NULL) ; if (checked) { ns_dstrιng_append(pds, " CHECKED"), ) ns_dstrιng_varappend(pds, "> ", label, " , NULL), static void Addlnputlnput(DM_TableInfo "tinfo, NS__DSTRING "pds, char "name, char "htmltag, char *html ag_data, mt formtype) { ns_dstrιng_varappend(pds, "<INPUT NAME=N"" , NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, "N" ", htmltag_data, ">Nn", NULL); ) /* Only put the text areas in for entry and update */ static void AddTextAreaInput(DM__TableInfo "tmfo, NS_DSTRING "pds, char "name, char "htmltag, char *htmltag_data, int formtype) { if ((formtype == ENTRY) | | (formtype == UPDATE)) { ns_dstrιng_varappend(pds, "<TEXTAREA NAME= "" , NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, "N" htmltag_data, "x/TEXTAREA>Nn", NULL), } else { ns_dstrιng_varappend(pds, "<INPUT " "NAME=N"", NS_FORM__VALUE_KEY, NS_FORM_SEPARATOR, name, "N" " "TYPE=N"tex N" SIZE=40>Nn", NULL); ) } static void AddDefaultlnput(DM_TableInfo 'tmfo, NS_DSTRING *pds, char 'name, int index, mt formtype) { char 'type = DM_ColumnValue(tinfo, index, "column_type") ; char 'boundstr = DM_ColumnValue(tinfo, index, "column_bound") int bound = atoi(boundstr) ; if (STREQ(type, "integer") I I STREQ(type, "mtl") I I STREQ(type, "decimal") I I STREQ I type, "double precision" ) ) { ns_dstπng_varappend (pds , " <INPUT " OatFom.c Sat Mar 18 21:36:16 1995 12 "NAME=N"" , NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, "N" "TYPE=N"textN" SIZE=10>Nn" , NULL); } else if ( (STREQ(type, "char") || STREQ(type, "character") j j STREQ(type, "varchar") ) it (bound '= 0)) { ns_dstrιng_varappend(pds, "<INPUT " ■ NAME=N"", NS_FORM_VALUE__KEY, NS_FORM_SEPARATOR, name, "N" "TYPE=N"textN" " "SIZE=", boundstr, " MAXLENGTH=", boundstr, ">Nn", NULL); } else if (STREQ(type, "charl")) { ns_dstrιng_varappend(pds, "<INPUT " "NAME=N" " , NS_FORM_VALUE__KEY, NS_FORM_SEPARATOR, name, "N" -TYPE=N"text " " "SIZE=1 MAXLENGTH=l>Nn", NULL); ) else if (STREQ(type, "boolean")) { char 'label; if ((formtype == ENTRY) | | (formtype == UPDATE)) ( label = "Unknown" ; } else if (formtype == SEARCH) { label = "EiCher" ; ) else { assert(0) ; } AddColValueRadioButton(pds, AddColValueRadioButton(pds, AddColValueRadioButton(pds, ns_dstrmg_append(pds, "Nn" ) else if (STREQItype, "date")) AddColNullInput(pds, name, AddDatelnput(pds, naune) ; ns_dstnng_append(pds, "Nn" ) ; } else if (STREQItype, "time")) { AddColNullInput(pds, name, formtype); AddTimeInput(pds, name) ; ns_dst ιng_append(pds, "Nn" ) ,- ) else if (STREQItype, "timestamp')) { AddColNullInpu (pds, name, formtype); AddTimelnput(pds, naune); AddDatelnput(pdε, name) ; ns_dstπng_append(pds, "Nn") ,- ) else { ns_dstrmg_varappend(pds, "<INPUT " "NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, "N" " "TYPE=N"textN" SIZE=40>Nn", NULL); } } static void AddColNullInput(NS_DSTRING *pds, char *name, mt formtype) { char 'label; if ((formtype == ENTRY) || (formtype == UPDATE)) { label = "Unknown",- } else if (formtype == SEARCH) { label = "Any" ; } else { assert(0) ; ) ns_dstrιng_varappend(pds, "<INPUT " "NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, NS_FORM_SEPARATOR, "NULL ' OatFora.c Sat Mar 18 21:36:16 1995 13 -TYPE=radio value=N"tN" CHECKED> ", label, " ", "<INPUT " "NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, NS_FORM_SEPARATOR, "NULLN" "TYPE=radio value=N"fN"> ", NULL); } static void AddTimelnput(NS_DSTRING *pds, char *naune) { time__t tt_now = time(NULL); struct tm *tm_now = localtime(ttt_now) ; char timestrfδ],- int hours; char *aunpm; if (tm_now->tm_hour == 0) { hours = 12; ampm = NS_FORM_AM; ) else if ( (tm_now->tm_hour > 0) tt (tm_now->tm_hour < 12) ) { hours = tm_now->tm_hour; ampm = NS_FORM_AM; } else if (tm_now->tm_hour == 12) { hours = tm_now->tm_hour; ampm = NS_FORM_PM; } else if (tm_now->tm_hour > 12) ( ampm = NS_FORM_PM; hours = tm_now->tm_hour - 12,- } else { assert(0) ; } sprintf(timestr, "%d:%02d", hours, tm_now->tm_min) ; ns_dstring_varappend(pds, "<INPUT " "NAME=N"", NS_FORM_VALUE_KEY, NS__FORM_SEPARATOR, name, NS_FORM_SEPARATOR, NS_FORM_TIME_KEY, "N" ", "TYPE=N"textN" SIZE=9 VALUE= "" , timestr, "N">", "<SELECT ", "NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARAT0R, name, NS_FORM_SEPARATOR, NS_FORM_AMPM_KE , "N">Nn" , NULL) ; if (ampm == NS_FORM_AM) { ns_dstring_varappend(pds, "<OPTION SELECTED> ", NS_FORM_AM, "Nn", "<OPTION> ", NS_FORM_PM, "Nn", NULL); } else { ns_dstring_varappend(pds, "<OPTION> ", NS_FORM_AM, "Nn", "<OPTION SELECTED> ", NS_FORM_PM, "Nn", NULL); ) ns_dstring_append(pds, "</SELECT>") ; ) static char "months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL},- static void AddDatelnput(NS_DSTRING "pds, char "name) { time_t tt_now = time(NULL); struct tm *tm_now = localtime(ttt_now) ; OatPoxm.c Sat Mar 18 21:36:16 1995 14 char mdaystr [3] ; char yearstr [5] ,- int i,- sprintf (mdaystr, "%d", tm_now->tm_mday) ; sprintf (yearstr, "%d", tm_now->tm_year + 1900); ns_dstring_varappend(pds, "<SELECT " "NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, NS_FORM_SEPARATOR, NS_FORM_MONTH_KE , "N">Nn", NULL); for (i = 0; i < 12; i++) { if (i == tm_now->tm_mon) { ns_dstring_varappend(pds, "<OPTION SELECTED>", months [i], "Nn", NULL); } else { ns_dstring_varappend(pds, "<OPTION>", months[i], "Nn", NULL) ; } } ns_dstring_varappend(pds, "</SELECT> ", "<INPUT " "NAME=N"", NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, NS_FORM_SEPARATOR, NS_FORM_DAY_KEY, "N" ", "TYPE=N"textN" SIZE=3 MAXLENGTH=2 VALUE=N"", mdaystr, "N">" , "<INPUT " "NAME= " " , NS_FORM_VALUE_KEY, NS_FORM_SEPARATOR, name, NS_FORM_SEPARATOR, NS_FORM_YEAR__KEY, "N" ", "TYPE=N"textN" SIZE=5 MAXLENGTH=4 VALUE=N"", yearstr, "N">", NULL); } static void AddSearchFields(DM__TableInfo -tinfo, NS_DSTRING *ds) { int i, max; assert(tinfo != NULL) ; assert(ds != NULL); max = FindMa (tinfo) ; for (i = 0; i < DM_ColumnCount (tinfo) ; ++i) { char *na_me; char *padded; name = DM_ColumnName(tinfo, i); if (naune == NULL) { continue; } padded = PadRight (name, max); ns_dstring_varappend( s, "<INPUT TYPE=\"checkboxN" " "NAME=N"", NS_FORM_SELECTED_KEY, NS_FORM_SEPARATOR, name, "N" CHECKED> ", padded, " ", NULL); AddOpSelect(tinfo, i, ds) ; Addlnput (tinfo, ds, name, SEARCH); ) ) static void AddCollectionFields(DM_TableInfo *tinfo, NS_DSTRING *ds) { OatFor .c Sat Mar 18 21 : 36 : 16 1995 15 int max, assert Itmfo '= NULL), assert(ds '= NULL) ; if (STREQ(DM_TableName(tinfo) , "ns_default_collectιon") ) { return,- ) max = FmdHaxltinfo) ; if (DM_ColumnIndex(tinfo,NS_URL_C0LUMN) '= -1) { char "padded, char "ops; ops = GetOps("doc" ) , asser (ops '= NULL); padded = PadRigh (NS_URL_COLUMN, max); ns_dstrιng_varappen (ds, "Fulltext of ' , padded, ' <SELECT SIZE=1 NAME=N"" , NS_F0RM_C0LL0PERATOR_KE , "\">" , NULL) while ("ops '= NULL) { ns_dstrιng_varappend(ds, "Nn<0PTI0N> ' , "ops, NULL), ++ops; ) ns_dstπng_varappend (ds , " Nn< /SELECT> <INPUT NAME=N " " , NS_F0RM_C0LLVALUE_KEY , " N " SIZE=40> Nn' , NULL ) , } } static void AddOpSelect(DM Tablelnfo "tinfo, int index, NS_DSTRING *ds) { char "ops; char "name, int first, assert(tinfo '= NULL), assert(ds '= NULL) ; assert(index >= 0 it index < DM_ColumnCoun (tinfo) ) , naune = DM_ColumnNaune(tιnfo, index), ops = GetOps(DM_ColumnType(tinfo, index)),- if (name == NULL | | ops == NULL) { return; } ns_dstrιng_varappend(ds, "<SELECT SIZE=1 NAME=N"", NS_FORM_OPERATOR_KEY, NS_FORM_SEPARATOR, DM_ColumnName(tmfo, index), "N">". NULL), first = 1, while ("ops '= NULL) ( if (first) { ns_dstnng_append(ds, "Nn<OPTION SELECTED: * "), first = 0; } else { ns_dstrιng_append(ds, "Nn<OPTION>") , OatFoxm.c Sat Mar 18 21 : 36 : 16 1995 16 ) ns__dstr mg_append ( ds , * ops ) ; ++ops ; } ns_dstrιng_append (ds , " Nn< /SELECT> " ) ; } static void AddOrderBys(DM_TableInfo "tinfo, NS_DSTRING *ds) { int norder, mt max,- char "ma-xStr; maocStr = DM_TableValue(tmfo, "table_maxorderby" ) , if ( axStr == NULL) { axStr = Ns_GetConfιgValue("MaxOrderBy") , } if (maxStr '= NULL) { max = atoi(maxStr) , } else { max = 3; } if (max > DM_ColumnCount(tinfo) ) { max = DM_ColumnCount(tmfo) , } ns_dstring_append(ds, "Order by:"); for (norder = 0; norder < max; ++norder) { mt nselect; char nameAttr[0x100] ; sprintf(nameAttr, "%s%s%d", NS_FORM__ORDERBY_KEY, NS_FORM_SEPARATOR, norder), ns_dstnng_varappend(ds, " <SELECT SIZE=1 NAME=N"", nameAttr, "N">Nn<OPTION SELECTED>" , NS_FORM_ORDERBY_NONE_KEY, NULL); for (nselect = 0, nselect < DM_ColumnCount(tmfo) , ++nselect) { char "name; name = DM_Colu_nnName( info, nselect); if (name == NULL) { continue; ) ns_dstπng_varappend(ds, "Nn<OPTION>* , name, NULL), } ns_dstnng_append (ds , " < /SELECT> " ) ,- } ns_dstrmg_append(ds , " Nn" ) ,- static char * * GetOps ( char * type ) { static char "numberopsU = { "=", "tgt;", "tit;", "igt;=", "ilt;=", "tlt;igt;", "is null", "is not null", NULL }; static char *textops[] = { OatForm.c Sat Mar 18 21:36:16 1995 17 "=", "ilt;igt;", "contains", "like", "not like", "is null", "is not null", NULL }; static char *docops[] = { "similar", "boolean", "is null", "is not null", NULL }; static char "basicops(] = { "=", "tlt;igt;", "lε null", "is not null", NULL }, char "ops; if (type == NULL) { ops = basicops; } else if (STREQ(type, "doc")) ( ops = docops; } elεe if (STREQ(type, "integer") | | STREQ(type, "double") | | STREQ(type, "decimal") j j STREQ(type, "numeric") I I STREQ(type, "date") | | STREQ(type, "time") | | STREQ(type, "timeεtamp") ) { opε = numberopε; } else if (STREQ(type, "text") | | STREQ(type, "character") j j STREQ(type, "char") II STREQ(type, "charl") | | STREQ(type, "varchar")) { ops = extops,- } else { ops = basicops; } return ops; static mt FιndMax (DM_TableInfo "tinfo) { int l , mt max ; assert(tinfo '= NULL), max = 0; for d = 0; l < DM_ColumnCoun (tinfo) , ++ι) { char "aame, name = DM_ColumnName(tinfo, l) , if (name != NULL) { mt len; len = strlen(name) ; if (len > max) { max = len; } } } return max; static char padded[0x200] static char * QetForm.c Sat Mar 18 21:36:16 1995 18 PadRight (char "name, int max) { char *p; int len; assert(name != NULL); assert(max > 0); len = strlen(name) ; if (len >= sizeof(padded) ) { return naune; } strcpy(padded, name) ; p = padded + len; max -= len; while (max--) { *p++ = ' ' ; } *p = 'NO' ; return padded; static char * PadLeft(char "name, int max) { char *p; int len; asser (name != NULL); asser (max > 0) ; len = strlen(name) ,- if (len >= sizeof(padded) ) { return name; ) p = padded; max -= len; while (max--) { *p++ = ' J ; } strcpy (p, naune) ; return padded; } /* * Spaces delimit items. * items can be in single quotes. * * Items cannot contain double quotes C"'s) because HTML doesn't * handle * them very wel1. * * * Always tries to deal with input; doesn't return any * errors. */ static char * Readltem(char "psrcstr, char "itembuf, int maxitemlen) { char c; char "stopchars: char "pos = itembuf; int escaped = 0; /* Get rid of leading white space */ OatForβ.c Sat Mar 18 21:36:16 1995 19 while (isspaceC"psrcstr) ) { Cpsrcstr)++; } if ("psrcstr == 'NO' ) { return NULL; } else if ("psrcstr == 'N'') { stopchars = "N' " ; ( • psrcstr)++,- } else { stopchars = " NtNnNr"; } while ( ( (pos - itembuf) < maxitemlen) it ( (c = "psrcstr) != 'NO') tt (escaped | | (strchr(stopcharε, c) == NULL))) { if (c == 'NN') { escaped = 1; } else { escaped = 0; *pos = c,- pos++; } Cpsrcstr)++,- } • pos = 'NO'; if (c != 'NO') { Cpsrcstr)++; /* jump past the delimiter character */ ) return itembuf; static int IsCacheable(char *table) { DM_TableInfo *tinfo; int i; tinfo = DM_GetTableInfo{table) ; if (tinfo == NULL) { return 0; ) for (i = 0; i < DM_ColumnCount(tinfo) ; ++i) { char *tagtype; char *type; type = DM_ColumnType(tinfo,i) ; if ( (type != NULL) ii (STREQttype, "date") || STREQ(type, "time") II STREQttype, "timestamp") ) ) { return 0; } tagtype = DM_ColumnValue(tinfo, i, "column_htmltag_type" ) ; if ((tagtype != NULL) it (STREQItagtype, NS_HTMLTAG_TYPE_SELECTSQL) I I STREQ(tagtype, NS_HTMLTAG_TYPE_SELECTSQLORNULL) I I STREQ(tagtype, NS_HTMLTAG_TYPE_AUTOINCR) ) ) { return 0; } } return 1; trgapag .c Mon Fab 27 18:26:19 1995 _ return NULL; } if (formp->first != NULL it formp->tag ! FORM_TAG) { formp = formp->first; } else ( while (formp != NULL tt formp->post NULL) { formp = formp->parent; } if (formp != NULL) { formp = formp->post; } } return page; static int EditForm(Para *para. Form *values) for (subpara = para->firεt; subpara != NULL; subpara = subpara->post) { if (EditFor Isubpara, values) != NS_OK) { return NS_ERROR; } } if tpara->text == NULL) { return NS_OK; ns_dstring_init (ttext) ; op = para->text; while (*op != 'NO') { if Cop != HTML_MARK) { ns_dstring_nappend(ttext, op, 1); ++op; } else { switch (HTML_tag(op) ) { case INPUT_TAG: if (EditInputTag(op, ttext, values) != NS_TRUE) { goto copy_tag; ) op += TagLen(op); break; case TEXTAREA_TAG: value = GetValueForTagNa e (values, op) ; if (value == NULL) { goto copy_tag; } /* append new value and END_TAG to text, skip op past END_TAG */ ns_dstring__nappend(ttext, op, TagLen(op) ) ; ns_dstring_append(ttext, value) ; op += Taglncr(op); ns_dstring_nappend(ttext, op - 5, 5) ; ■rgapage.c Mon Fab 27 18:26:19 1995 3 break; case SELECT_TAG: if (EditSelectTaglop, ttext, values) != NS_TRUE) goto copy_tag ,- } op += Taglncr (op) ,- break ; default: /* just append all other tags */ copy_tag : ns_dstring_nappend (ttext, op, TagLen(op)),- op += TagLen(op); break ,- } } } ns_free(para->text) ; ns_dstring_export (ttext, t (para->text) , ttlen, ttmax); para->tlen = (short) tlen; para->tmax = (short) tmax; return NS_OK; static int EditlnputTaglchar *op, NS_DSTRING "text, Form *values) { struct attribs *atts; value = GetValueForTagName(values, op); if (value == NULL) { return NS_FALSE; } if (HTML_HasAttr(op, buf, BUFSIZE, "TYPE")) { if ( !strcasecmp(buf, "text")) { type = TEXT; } else if ( ! strcasecmp(buf, "password")) { type = TEXT; ) else if (! strcasecmp(buf, "checkbox")) { type = CHECK; ) else if (! strcasecmp(buf, "radio")) { type = RADIO; } else { return NS_FALSE; /* unknown type - don't edit */ } } else { type = TEXT; /* default type */ trgapaga.c Mon Fab 27 18:26:19 1995 4 } ns_dstnng_ιnιt (ttag) ,- switch (type) { case TEXT: /* copy over all attributes but an existing VALUE */ ns_dstnng_append(itag, " " ) ; for (atts = HTML_GetAttrs(op) ; atts->name != NULL; ++atts) { if (atts->present it (strcmp (atts->name, "VALUE") '= 0)) { ns_dstnng_append(itag, atts->name) ,- ns_ds tr ιng_append ( t tag , " = N " " ) ; ns_dstrιng_nappend(ttag, atts->val, atts->len) ; ns_ds rιng_append ( ttag , " " " ) ; } } /* add the new VALUE attribute "/ ns_dstπng_append (ttag , "VALUE=N " " ) ; ns_dstrιng_append(itag, value), ns_dstnng_append (ttag, " " " 1 , break; case CHECK: if ( ' HTML_HasAttr(op, buf, BUFSIZE, "VALUE")) { return NS_FALSE; /* weirdness - don't edit */ } if (strcmp(value, buf) '= 0) { return NS_FALSE; /* nothing to check */ } if (HTML_HasAttr(op, buf. BUFSIZE, "CHECKED")) { return NS_FALSE; /* already checked */ ) /* copy over all attributes */ ns_dstnng_append(itag, " "); for (atts = HTML_GetAttrε(op) ; atts->name '= NULL, ++atts) { if (atts->present) { ns_dstrιng_append(ttag, atts->name) ; ns_dstring_append(ttag, "=N"") ; ns__dstrmg_nappend(ttag, atts->val, atts->len) ,- ns_dstrιng_append(ttag, "N" ") ; } } /* add check */ ns_dstrιng_append(itag, "CHECKED") ; break; case RADIO: ischecked = HTML_HasAttr(op, buf, BUFSIZE, "CHECKED"); if ( 'HTML_HasAttr(op, buf, BUFSIZE, "VALUE")) { return NS_FALSE; /* weirdnesε - don't edit */ if (strcm (value, buf) == 0) needscheck = 1; } else { •rgapaga.c Mon Fab 27 18:26:19 1995 5 needscheck = 0; } if ((needscheck it ischecked) | | (ineedscheck tt ϋschecked)) ( return NS_FALSE; /* nothing to check or uncheck */ ) /* copy over all attributes but an existing CHECKED » / ns_dstring_append(itag, " " ) ,- for (atts = HTML_GetAttrs (op) ; atts->name != NULL; ++atts) { if (atts->present it (εtrcmp(atts->name, "CHECKED") != 0)1 { ns_dstring_append(ttag, atts->name) ; ns_dstring_appeπd(ttag, "=N " " ) ; ns_dstring_nappend(ttag, atts->val, atts->len) ; nε_dεtring_append(ttag, "N" " ) ; } ) /* add CHECKED if needed */ if (needεcheck) { ns_dstrmg_append (ttag, "CHECKED") ,- } break,- } / * append this tag to the text dstπng * / tag_len = ns_dstring_length ( ttag ) ; head [ 0 ] = HTML_MARK; head [ l ] = tag_len / 256 ; head [2 ] = tag_len % 256 ; head [3 ] = INPUT_TAG; nε_dεtring_nappend ( text , head , 1 ; ns_dstring_nappend ( text , ns_dstπng_value (ttag ) , tag_len ) ,- ns_dstring_f ree (ttag ) ,- return NS_TRUE; static mt EditSelectTag (char 'op, NS_DSTRING "text, Form "values) fieldname = GetFieldNameForTagName (values, op), for (i = 0; i < values->NumFields; ++i) { if (strcasecmp(fieldname, values->fields [i] .name) == 0) { ns_sstack_push(topts, values->fields [i] .value); } } if (opts == NULL) { return NS_FALSE; /* not interested - don't edit */ ■rgapagβ.c Mon Fab 27 18 :26 : 19 1995 ) end = op + Taglncr(op) - 5; next = op + TagLen(op); ns_dstπng_mιt (tout; ; ns_dstrιng_mιt (topt ) ; firstSelected = 0; firεt = 1; while (next <= end) { if ("next '= HTML_MARK) { /* accumulate the text */ ns_dstπng_nappend(topt, next, 1), ++next; ) else { if ( (HTML_tag(next) '= OPTION_TAG) ii (HTML_tag(next) '= END_TAG) ) { /* some weird tag with the select */ ret = NS_FALSE; goto done; ) /* The first <0PTI0N> tag is skipped. */ if (first) { first = 0; } else { char ind; /* first trim the string */ p = opt.string; while (isspaceCp) ) { ++p; } ns_trιm(p) ; /* see if it should have a selected or normal tag */ isselected = 0; ind = ns_sstack_search(opts, p, strcmp) ,- if (ind '= -1) { ns_free (ns_sstack_delete (topts , ind) ) ; if ( ! firstSelected) { firstSelected = 1 ; isselected = 1 ; } } / * append the original string * / AddOptionTag ltout , opt . string , isselected) ; } ns_dstrιng_trunc (topt , 0 ) ,- next += TagLen(next) ,- } } while (ns_sstack_pop (topts , tvalue) == NS_TRUE) { isselected = 0 : if ( ! firstSelected) { firstSelected = 1 ; isselected = 1 ; } AddOptιonTag(iout, value, isselected) ; ns_free(value) ; aergepage.c Mon Fab 27 18 : 26 : 19 1995 7 } ns_dstring_nappend(text, op, TagLen(op)); ns_dstring_nappend(text, out.string, out.length) ns_dstring_nappend(text, end, 5); ret = NS_TRUE; done: ns_dstring_free(topt) , ns_dstring_free(tout) ns_sstack_free(iopts) return ret; ) static void AddOptionTag(NS_DSTRING "pds, char "string, int isselected) { static char option!] = {HTML_MARK, 0, 0. OP ION_TAG} ; static char selectedOption!] = {HTML_MARK, 0, 9, OPTION_TAG, ' ','S','E','L','E','C','T','E','D'}; if (isselected) { ns_dstring_nappend(pds, selectedOption, sizeof (selectedOption) ) ) else { ns_dstring_nappend(pds, option, εizeof(option) ) ; } ns_dstring_varappend(pds, string, "Nn", NULL); } /* * GetValueForTagName - Return the value from {values} which corresponds * to the NAME attribute in the form {tag}. The tag NAME attribute must * also be prefixed NS_FORM_VALUE_KE . */ static char * GetValueForTagName(Form *values, char *tag) { char *fieldname = GetFieldNameForTagNa e(values, tag) ,- if (fieldname == NULL) { return NULL; ) else { return GetFormValue(values, fieldname); } ) static char * GetFieldNameForTagName(Form "values, char "tag) { static char buf[0x100],- char *sep; /* Find the NAME attribute. */ if ( !HTML_HasAttr(tag, buf, BUFSIZE, "NAME")) { return NULL; /' no NAME weirdness */ } /* Find the end of the NAME attribute class. */ sep = strchr(buf, *(NS_FORM_SEPARATOR) ) ; if (sep == NULL) { return NULL; /* not in class:name form */ } /* Make sure this NAME is in the VALUE class. */ *sep = 'NO' ; ■argapage.c Mon Fab 27 18:26:19 1995 8 if (strcmp (buf, NS_FORM_VALUE_KEY ) != 0) { "sep = *(NS_FORM_SEPARATOR) ; return NULL; /* not in the VALUE class */ } /* Return the first value with the matching name. */ "sep = * (NS_FORM_SEPARATOR) ; return sep+1; nlink.c Sun Fab 26 17:22:31 1995 1 /* nlink.c. Takes the page as a big string and returns List of Hyperlinks Unless MaxRetrievals is 0, nlink will assume the dbms is open and do retrievals against it */ (.include "nsd.h" #ιnclude "nlp.h" ♦ifdef DEBUG void PrintHtmlPage (HtmlPage "page) ,- ♦endif /* Preferences: MinAnchorWeight MinHlinkWeight MaxRetrievals MinHitWeight MaxHlinksPerAnchor 1. Call NLP 2. Extract NG's " 3. Filter out ones that are already anchorε (or part of anchors) 4. Assign a context-free likely-hood-of-being-an-anchor weight to each phrase. 5. Formulate IR queries for those phrases above a certain threshold * remove stop words (if necessary) * AND terms together * require adjacency (if possible) * words in the title count for more 6 Send the queries 7. Factor in the weighted return values 8. Return the best results */ List "nlink (HtmlPage "page, char "collection. Form "prefs, char "pageurl) { Textobj "textobj; List "ngs, *m. List 'hlinks = NULL; Liεt 'curhlinks; char 'hold; float MinAnchorWeight; float MinHlinkWeight; t MaxRetrievals; float MmHitWeight; mt MaxHlinksPerAnchor; int retrievals; ♦ifdef DEBUG PrintHtmlPage (page) ,- ♦endif nlink.c Sun Fab 26 17:22:31 1995 2 if ( (hold=GetFormValue(prefs, "MinAnchorWeight") ) '= NULL) { assert(hold) ; sscanf(hold, "%f",tMinAnchorWeight) , } if ( (hold=GetFormValue(prefs, "MinHlinkWeight") ) '= NULL) { assert(hold) ; sscanf(hold, "%f" ,iMιnHlιnkWeιght) , ) if ( (hold=GetFormValue(prefs, "MaxRetrievals" ) ) '= NULL) { assert(hold) ; sscanf(hold, "%d" ,tMaxRetrievals) ; } if { (hold=GetFormValue(prefs, "MinHitWeight" ) ) >= NULL) { assert(hold) ; sscanf(hold, "%f" ,iMinHitWeight) , ) if ( (hold=GetFormValue(prefs, "MaxHlinksPerAnchor") ) '= NULL) ( assert(hold) , sscanf(hold, "%d",tMaxHlinksPerAnchor) , } ns_memory_trace(NS_OFF) ; textob 3 = HtmlPage2Express(page) , if (textob: == NULL) { return NULL, } ngs = GetNgs (textob 3 ); /* each ng is not copied */ ngs = DeleteDuplicates (ngs.NgEqual) , for (m=ngs;m'=NULL,-m = rest( )) { m->weιght = NgAnchorProb( (Liεt *) m->flrεt) , ) ngs = WeightSort(ngs) , ngs = DeleteLowElements(ngs,MinAnchorWeight) , retrievals = 0, for (m=ngs;m!=NULL;m = m->rest) { if (retrievals >= MaxRetrievals) curhl ks = NULL; else { curhlmks = Ng2Hlιnks(m->flrεt, m->weιght, collection, MinHitWeight, MaxHlinksPerAnchor, pageurl) ; retrievals**; } hiinks = nconc(curhlmks.hiinks) ; ) hlinks = DeleteLowElements(hlinkε,MinHlinkWeigh ) , FreeList(ngs, ULL) , FreeTextob 3 (textob 3 ) .- return(WeightSort(hlinkε) ) , nlink.c Sun Fab 26 17:22:31 1995 3 } void PrmtHyperlink (FILE "fp Hyperlink "hlink HtmlPage "page) { char "url, char 'showurl, char 'title, fprintf (fp, "Hyperlink --Nn") fprιntf(fp ' Anchor (pnum %d, start %d, length %d) hlmk->pnum, hlmk->anchor_start, hlιnk->anchor_length) if (page '= NULL) fprintf (fp,'%sNn", PageGetStπng (page hlιnk->pnum, hlιnk->anchor_start hlιnk->anchor_length) ) , else fprintf (fp, "">"\n") , if (hlιnk->url == NULL) url = "NONE' else url = hlιnk->url fprintf (fp, " URL %sNn ,url) if (hlιnk->showurl == NULL) showurl = url else showurl = hlιnk->showurl, fprintf (fp, " SHOWURL %sNn .showurl) if (hlιnk->tιtle == NULL) title = " " , else title = hlιnk->tιtle, fprintf (fp," TITLE %sNn" title) Hyperlink 'NewHyperlink ( t pnum int start, int length * char "url char 'showurl, char "title) Hyperlink "hlink, hlink = (Hyperlink *) ns_malloc (sizeof(Hyperlink) hlιnk->pnum = pnum, hlιnk->anchor_start = start, hlιnk->anchor_length = length, hlιnk->url = ns_strdup(url) , hlιnk->showurl = ns_strdup(showurl) , hlmk->tιtle = ns_strdup( itle) , return(hlink) , } void FreeHyperlink (Hyperlink "hlink) { ns_free(hlmk->url) , ns_free(hlιnk->showurl) , ns_free(hlιnk->tιtle) nε_free(hlink) , ) ♦ifdef DEBUG nlink.c Sun Fab 26 17:22:31 1995 4 /* Returns number of the next paragraph */ ♦include "morehtml.c" int PrintHtmlPara (Para "para, int pnum, int indent) { char "pt; Para *subpara; int ta ; int i ; /* Process self */ for (i=0,-i<indent; i++) fputc( ' ' , stdout) ,- printf ("Para %d (%d)",pnum, para->pnum) ; if (key2names [tag=para->tag] ) { printf (" (%s) " ,key2names[tag] ->naune) ; ) if ( (pt=para->text) != NULL) { printf (" : ") ; while Cpt!='N0') { if (*pt==HTML_MARK) { tag = ((unsigned char *) pt) [HTML_POS_TAG] if (tag == END_TAG) { printf ("<END>") ,- ) else if (key2names [ ag] ==NULL) { printf ("<OTHER>") ; } else { printf ( "<%s>" ,key2names [tag]->name) ; } pt+=TagIncr (pt) ; } else { putc (*pt,stdout) ; pt++; } ) printf (" : " ) ,- ) printf ( "Nn" ) ; pnum++; /* Process children */ subpara=para->first; while (subpara!=NULL) { pnum=PrintHt_nlPara (subpara,pnum, indent+5) ; subpara=subpara->post; } return (pnum) ; } void PrintHtmlPage (HtmlPage 'page) { int pnum=0; Para 'para = page->first; initkeynames ( ) ; printf ("HTML Page n"); while (para!=NULL) { pnum=PrintHtmlPara(para,pnum, 0) ; para=para->post,- ) } ♦endif nad.c Tua Mar 21 20:32:37 1995 ♦include "nsd.h" ♦include <pwd.h> ♦include <sys/stat.h> ♦include <sιgnal.h> ♦include <sys/waιt.h> ♦include <sys/socket.h> ♦include <netdb.h> ♦include <sys/resource.h> static char rcsid[] = "SHeader. /current/src/nsd/RCS/nsd.c,v 1.25 1995/03/22 04:32:36 3imbo Exp S" ; static void usagednt argc, char **argv) ; static void TableAlert(void) , static void ConfigAlert(void) , static void SetShutdown(voιd) ; static void SetRestar (void) ; static int Ns_DιrReadable(char *dιr) , static void About(Ns_Conn "conn); extern char *mι_getsysparam(char *, char *), ♦define MI_SYSPARAMS "MI_SYSPARAMS" static Nε_Op nsOps[] = { {"NS", "GET", NS_OP_GetEntryForm, GetEntryForm, 0} {"NS", "GET", NS_OP_GetUpdateForm, GetUpdateForm, 0}, {"NS", "GET", NS_OP_GetUpdateOrEntryFoπτι, GetUpdateOrEntryFor , 0}, {"NS", "GET", NS_OP_GetSearchFormPιcker, GetSearchFormPicker, 0), {"NS", "GET", NS_OP_GetSearchForm, GetSearchForm, 0}, {"NS", "GET", NS_OP_GetLocalHιlιtedPage, GetHilitedPage, 0), {"NS", "GET", NS_OP_GetRemoteHιlιtedPage, GetHilitedPage, NS_OP_FORK} , {"NS", "GET", NS_OP_MoreLιkeThιs, MoreLikeThis, NS_OP_FORK | NS_OP_DB} , {"NS", "GET", NS_OP_GetMetaTables, GetMetaTables, 0}, {"NS", "GET", "Archive", ArchiveGET, 0}, {"NS", "PUT", "Archive 1 , ArchivePUT, 0), {"NS", "POST", NS_OP_SearchQBF, SearchQBF, 0), {"NS", "GET", NS_OP_SearchQBF, SearchQBF, 0}, {"NS", "POST", NS__OP_InsertRow, InsertRow}, {"NS", "POST", NS_OP_UpdateRow, UpdateRow}, {"NS", "POST". NS_OP_DeleteRow, DeleteRow} , {"NS", "GET", NS_OP_GetAsset, GetAsset}, {"NS", "PUT", NS_OP_Navιlιnk, Navilink, NS_OP_FORK | NS_OP_DB} , {"NS" , "GET", NS_OP_About, About) , {NULL, NULL, NULL, NULL, 0} static DM_Alert nsdAlerts[] = { {"ns_tables_alert" , 0, TableAlert}, {"ns_permιssιons_alert" , 0, Ns_InιtPermιssιons) , {"ns_users_alert", 0, Ns__InιtPermιssιons) , Cns__coπfιg_alert" , 0, ConfigAlert) , {NULL, 0, NULL) }, Daemon me, extern mt optind; mt mam(int argc, char **argv) OatFoxm.c Sat Mar 18 21:36:16 1995 20 } OetHilitadPaga.c Sun Fab 26 19 :48:37 1995 1 ♦include "nsd .h" static char rcsιd[] = "$Id: GetHilitedPage.c,v 1.8 1995/02/14 03:06:23 3 ιmbo Exp $" /* formdata: URL=foo;terms=a,b,c */ void GetHilitedPage (Ns_Conn "conn) ( char "url,- char 'terms, char 'collection; char 'html; if (conn->form == NULL) ( return Ns_ReturnBadUrl(conn) ,- } if ((terms = GetFormValue(conn->form, "terms" ) ) == NULL) { terms = "" ; ) collection = GetFormValue(conn->form, "collection") , if ((url = GetFormValue(conn->form,NS_FORM_URL_KEY) ) == NULL) { return Ns_ReturnError (conn, "Did not specify URL to be hilited."); ) if Curl == '/' ) { switch (Ns_CheckUrl(conn, url)) { case NS_ALLOWED: html = HiliteURL (ur ,terms, collection) ,- break,- case NS_FORBIDDEN: return Ns_ReturnForbιdden(conn) , break,- case NS_UNAUTHORIZED return Ns_ReturnUnauthoπzed(conn) , break; default return Nε_RetumError(conn, "Could not check %s permission of " "URL %s", conn->requeεt->method, url); ) } else { html = HiliteURLIurl.termε,collection) , } if (html == NULL) { Ns_ReturnError(conn, "Could not hilite page"); } else { Ns_ReturnHtml(conn, 200, html, -1) ; ) } MoraLikβThi .c Sun Fab 26 19:48:38 1995 1 ♦include "nsd.h" static char rcsιd[] = "$Id: MoreLikeThis.c,v 1.6 1995/02/14 03:06:23 3 ιmbo Exp $' /* Takes an optional argv[2] */ MoreLikeThis (Ns_Conn 'conn) { char 'querystr; Form * uery; char 'collection; char "url ,- if (conn->form == NULL) { return Ns_ReturnBadUrl (conn) ; } if (conn->requeεt->urlc == 2) { if ((collection = Ns_GetConflgValue ( "DefaultCollection" ) ) == NULL) { collection = "ns_pages"; } } else if (conn->request->urlc == 3) { collection = conn->request->urlv[2] ; } else { return Ns_ReturnBadUrl (conn) ; } if ((url = GetFormValue(conn->form, NS_FORM_URL_KEY) ) == NULL) { return Ns_ReturnError (conn, "Did not εpecify URL to be hilited."); } querystr = Ns_Url2Querystr (url) ; if (querystr == NULL) ( return Ns_ReturnError (conn, "Could not construct query from page."); } query = NewForm(NULL, NULL, 0); AppendFormField(query, NS_FORM_VALUE_KEY NS_FORM_SEPARATOR NS_BODY_COLUM , querystr, 0, 0) ; AppendFormField(query, NS_FORM_SELECTED_KEY NS_FORM_SEPARATOR NS_TITLE_COLUMN, "CHECKED", 0, 0); AppendFormField(query, NS_FORM_SELECTED_KEY NS_FORM_SEPARATOR NS_URL_COLUM , • CHECKED", 0, 0); DoSearchQBF(conn, query, collection); DelForm(query) ; Navilink.c Sun Fab 26 17:22:30 1995 ♦include "nsd.h" ♦include "nlp.h" static void AppendHyperlink (NS_DSTRING "pds, Hyperlink "hlink, float weight) Navιlιnk(Ns_Conn "conn) { HtmlPage "page; Form "forms. Form "prefs, "userprefs; char "put; char "pageurl, List "hlinks, *m; Hyperlink "hl k, char "collection,- NS_DSTRING ds, if (conn->content == NULL) return Ns_ReturnError(conn, NS_ERR_NOPAGE) , pageurl = NULL; if (conn->form '= NULL) { pageurl = GetFormValue(conn->form, NS__FORM_URL_KEY) ; pageurl = Ns_RelatιveUrl(pageurl) , } prefs = NewFormt"prefs' AppendFormField{prefs, AppendFormField(prefs, AppendFormField(prefs, AppendFormField(pre s, AppendFormField(prefs, AppendFormField(pre s, AppendFormFiel (pre s, Ns__OverrιdeWιthConfιgs(prefε) , if (conn->form) { forms = SplιtForm(conn-> orm) , if ( (userprefs = FιndForm(forms,NS_FORM_PREF_KEY) ) '= NULL) { MergeForms(prefs,userprefs) , ) DeleteForms(forms) ; /* collection comes from (in priority order) : 1. arg [2] 2. DefaultSmartLinkCollection pref from client 3. DefaultSmartLinkCollection pref from server 4. DefaultCollection from client 5. DefaultCollection from server 6. DefaultCollection from hardcoded default above (ns_pages) */ if (conn->request->urlc == 3) { collection = conn->request->urlv[2] ,- } else if (conn->request->urlc == 2) { collection = GetFormValue(prefs, "DefaultSmartLinkCollection" ) if (collection == NULL) { collection = GetFormValue(prefs, "DefaultCollection") , } } else { return Ns_ReturnError(conn, NS_ERR_INVALIDURL) ; Na-ri ink.c Sun Fab 26 17:22:30 1995 2 ) /* Read the page */ put = conn->content, page = FillHtmlPage (NULL, parse_stnng tput) , hlinks = nlin page, collection, prefs, pageurl), /* Write out the links */ /* format is pnum, start, length, weight, URL • / ns_dstrιng_ιnιt(ids) , m = hlinks, while (m '= NULL) { hl k = (Hyperlink *) m->fιrst, AppendHyperlink(ids,hlιnk,m->weιght) , m=m->res , } KillHtmlPage(page) , FreeList(hlinks,FreeHyperlmk) , DelFor (prefs) , Ns_ContentHeaders(conn, 200 "application/x-navilmkε ', dε length), Ns_WrιteConn(conn, ds.string, ds length), ns_dstrιng_free(tds) , } /* Each hyperlink corresponds to 3 lines pnum, start, length, weight, URL showurl title */ static void AppendHyperlink (NS_DSTRING "pds. Hyperlink "hlink, float weight) { char "url, if (hlιnk->url == NULL) url = "NONE", else url = hlmk->url, ns_dstrιng_pnntf (pds, "%d %d, %d %f, hlmk->pnum, hlmk->a_nchor__star , hi ink- >anchor_length , weight) ; ns_dstrιng_varappend(pds, url, " Nn , hlιnk->showurl , "Nn", hlιnk->tιtle. "Nn", NULL), ♦ifdef DEBUG_NLINK fprintf (stderr,"%d, %d, %d, %f, %sNn" , hlιnk->pnum, hlιnk->anchor_star , hlmk-_>anchor_length , weight , url) , fprint (εtderr, "%sNn" ,hlιnk->showurl) , fprintf (stderr, "%sNn" ,hlιnk->tιtle) , ♦endif } Ng2Blinka .c Sun Mar 12 22 : 42 : 34 1995 1 ♦include "nsd . h" ♦include "nlp . h" static char *Ng2stπng (List *ng ) ( NS_DSTRING ds ; List *m = ng, mt first = 1 , assert (ng ' =NULL) ; ns__dstπng_ιnιt (ids ) ; while (m '= NULL) { if (first) first = 0; else ns_dstrιng_append(tds, " ') ns_dstrιng_append(ids, ( (Token *) m->first)->stem) , m=m->rest, > return ns_dstnng_movestrιng(ids) ; } /* Takes an NG and minimum weight and returns a newly malloc'ed SQL command that selects the ns_url, nε_tιtle, and ns_body_weiq.it of all the pageε that match with at leaεt that weight, ordered by weight max to least. It is Illustra-specific right now, but is the only part of Navilmkmg that is */ static char *Ng2SQL (char 'ngstr, char 'collection, float mmweight) { NS_DSTRING ds; char mmweightstr(16) ; char 'quotedvalue = ns_enquote(ngstr) , sprintf(mmweightstr, "%f" ,mιnweιght) , ns_dstrιng_ιnιt(tdε) , ns_dstring_varappend(ids, "select ' , NS_URL_C0LUM , " , " , NS_BODY_COLUMN, ' , ' , NS_TITLE_COLUMN, ', "WeightContainε( ' " , collection, "_by_", NS_BODY_COLUMN, " ' , " , "ctid,AndTerms( ' " , quotedvalue, ")) as " ,NS_B0DY_C0LUMN, "_weιght from ", collection, " where " , NS_B0DY_C0LUMN, "_weιght > " , mmweightstr , " order by " , NS_B0DY_C0LUMN , "_weιght desc , ' , NULL) , return ns_dstrmg_movestrιng(ids) , /* Formulates the queries, sends them off, and builds the links */ List *Ng2Hlιnkε(Lιst *ng. Hg2Blinka.c Sun Mar 12 22:42:34 1995 2 float ngweigh , char 'collection, float MinHitWeight, int MaxHlinksPerAnchor, char "pageurl) { char "ngstr = Ng2strιng(ng) ; char "sql = Ng2SQL(ngstr,collection,MinHitWeight) ; Form "hit; List "wlist = NULL; float body_weιght,- char "termsstr = NULL; int i; char "url, "showurl; char "title; char buf[NS_MAXURLSIZE] ; if ((hit = DM_Select(sql) ) '= NULL) { ι = l; while (DM_GetRow(hι ) == DM_0K) ( if d > MaxHlinksPerAnchor) { /* DM_Cancel() ; */ DM_Flush() ; break,- } url = GetFormValue(hit, S_URL_COLUMN) ; if (pageurl tt (STREQ(url,pageurl) ) ) { continue; } if (termsstr == NULL) { termsstr = Query2Terms(ngstr) ; } sscanf(GetFormValue(hit,NS_BODY_COLUMN "_weιght" ) , "%f" ,ibody_weιght) if ((title = GetFormValue(hit,NΞ_TITLE_COLUMN) ) == NULL) { title = url; ) showurl = BuildHiliteURLIurl, termsstr, collection); /* HACK' this should call something more general' */ if <url[0] == '/') ( /* the url is server-relative */ sprintf (buf, "%s%s" ,me.self,url) ; url = buf; ) wlist = cons(NewHyperlink (NgPnum(ng) , NgStart(ng) , NgLength(ng) , url, showurl. title) , wlist) ; wlιst->weιght = body__weig.it * ngweight, ι++ ; ) DelForm(hιt) ; } ns_freetsql) ; ns_free(ngstr) ; ns_free(termsstr) ; return wlist; Mg2Blinka.c Sun Mar 12 22:42:34 1995 ) HgλnchorProb.c Sun Fab 26 17:22:30 1995 1 ♦include "nsd.h" ♦include "nlp.h" ♦include <math.h> int bget_lιne (FILE "fp, char* linestart, char "retime, int maxlinelength) int lget_line (FILE "fp, char* linestart, char "retime, int maxlinelength, long start, long end) ,- long GetOccs (FILE *fl, char "word) ; mt FilterNg (List *ng) ,- static FILE "NgAnchorFl = NULL; static long NgAnchorTotal = 0; void ImtNgAnchorProbs (char "dataroot) { NS_DSTRING ds ; static char line [MAXFREQLINE] , ns_dεtrιng_ιnιt (ids) ; nε_dstrιng_varappendIids,dataroot , "/" ,MS_FREQLEX_FILE, NULL) ; NgAnchorFl=fopen(ds .string, "r" ) ; if (NgAnchorFl == NULL) ( nε_dstrιng_free (ids) ; Ns_Fatal ( "Couldn' t open frequency lexicon: %s " , ds .string) ; } ns_dstrιng_free(tds) ; NgAnchorTotal = atol ( fgets (line, MAXFREQLINE, gAnchorFl ) ) ,- } void FreeNgAnchorProbs ( ) { if (NgAnchorFl '= NULL) { fclose (NgAnchorFl) ,- } ) float NgAnchorProb (List *ng) { long ngoccs,- long tokoccs; float freq; char "stem; assert (NgAnchorFl != NULL); if (FilterNg(ng) ) return 0; ngoccs=0; for ( ;ng! =NULL;ng=ng->rest) { if (( (stem= ( (Token *) ng->first) ->stem) '= NULL) it (strcmp(stem, "and" ) != 0) tt (strcmp(stem, "a") '= 0) it (strcmp(stem, "an" ) '= 0) it (strcmp(stem, "the" ) '= 01) { tokoccs = GetOccs (NgAnchorFl , stem) ; ngoccs+=tokoccs ; } } if (ngoccs == 0) return 1 ; NgλnchorProb.c Sun Fab 26 17:22:30 1995 2 else ( freq = (float) ngoccs/NgAnchorTotal ; /* return (freq) ; */ return (1 - 1/ (- (log (freq) /log(2) ))) ,- ) } /* Don't allow phrases that contain stopwords except for "the" , "a" , and "an" */ int FilterNg (List *ng) { char "stem; for ( ;ng ' =NULL,-ng=ng->rest) ( if (( (stem= ( (Token *) ng->firs ) ->stem) '= NULL) it (strcmplstem, "a") '= 0) it (strcmp(stem, "an" ) '= 0) tt (strcmp(stem, "the" ) '= 0) it (ιsStopWord(stem) ) ) { return NS_TRUE; ) } return NS_FALSE; long GetOccs (FILE *fl, char "word) { static char line [MAXFREQLINE] , static char star [MAXFREQLINE] , int len; if ( (len=strlen(word) ) > (MAXFREQLINE - 2)) return 0; else { strcpy (start,word) , star [len] =' start [len+l) =' NO' ,- ) if (bget_lιne ( fl , start, line,MAXFREQLINE) == 0) return 0; else { return (atol (strrchr (line, ' ')+D); ) ) /* Get a line from a sorted file using binary search*/ /* Assumes retime is at leaεt maxlinelength */ /* Won't necessarily return the first line that matches */ int bget_lιne (FILE "fp, char* linestart, char "retime, int maxlinelength) { char c, *matchlιne; long region_start=0; long regιon_end, curpos; fseek (fp, 0,2) ; regιon_end=ftell (fp) , curpos=0; while (1) curpos=floor( (regιon_end+regιon_start) /2 ) ; fseek(fp, curpos , 0) ,- whιle( ( (c=fgetc(fp) ) '='Nn' ) it (c'=EOF)), curpos=ftell I fp) ; NgλnchorProb.c Sun Fab 26 17:22:30 1995 if(curpos==regιon_end) return lget_lιne(fp, linestart,re line,maxlinelength,regιon_s art,r egιon_end) , =fgetc(fp) ) ) matchlιne++, if (*matchlιne==' NO' ) /* Found matching line */ { fseek(fp,curpos,0) , fgets (retime,maxlinelength, fp) , return 1, } if (*matchlιne>c) regιon_εtart=curpos, else regιon_end=curpos ) } /* Same as bget_lιne, but uses SLOW linear search. "/ mt lget_lιne (FILE "fp, char* linestart, char "retime, mt maxlinelength long start, long end) { char curline[maxlinelength] , int lιnestartlength=strlen(linestart) , fseek(fp,start,0) , while ( (fgets(curline,maxlinelength, fp) '= NULL) it (ftell (fp)<=end) ) { if (strncmp(linestart,curline, linestartlength) == 0) { strcpy(retime,curline) return 1, ) } return 0, TclOp.c Mon Mar 20 21:17:26 1995 1 ♦include "nsd.h" ♦include "tcl h" ♦include " i.h" ♦include <sιgnal.h> ♦include <sys/waιt.h> extern int Mι_Inι (Tcl_Interp "interp, char "library), static void SetFormlchar *, Form *), static void SetDBConn(voιd) , static void LogError(void) , static int RegisterCmdIClientData, Tcl_Interp *, int, char **), static int HttpTimeCmd(ClientData, Tcl__Interp *, t, char **), static int ReturnFileCmd(ClientData, Tcl_Interp *, int, char **) static int LogCm (ClientData, Tcl_Interp *, int, char **), static mt OpenUrlCm (ClientData, Tcl_Interp *, int, char **), static int TmpNamCmdlClientData, Tcl_Interp *, mt, char **), static int Re oveFileCmdtClientData, Tcl_Interp *, int, char **), static int GuessSuffιxCmd(ClιentData, Tcl_Interp *, int, char ** static int GetHostCmd(ClientData, Tcl_Interp *, int, char **), static int TraceCmd(ClientData, Tcl_Interp *, int, char **) static int WriteCmd(ClientData, Tcl_Interp *, int, char **), static int HeadersCm (ClientData, Tcl_Interp *, int, char **), static int StrιpHtmlCmd(ClιentData, Tcl_Interp *, int, char **) static Ns_Conn "lastConn = NULL, static Tcl_Interp "interp = NULL, static char remit[] = "source $NS(library) /remit tcl', static char ιnιt[] = "source $NS(library) /init. cl" static FILE "accessLog = NULL, static Tcl_Trace currentTrace, static void Trace(ClientData ClientData, Tcl_Interp "mterp, int level, char "command, int CcmdProc) (), ClientData cmdClientData, int argc, char "argv) fprintf(ClientData, "Tcl[%d]- %sNn", level, command) static int TraceCmd(ClientData dummy, Tcl_Interp " terp, t argc, char "argv) { mt level, if ((argc '= 2) it (argc '= 3)) { Tcl_AppendResult(interp, "wrong ♦ of args should be \ " , argv[0], " level 'fileld'", NULL), return TCL_ERR0R, ) if (Tcl_GetInt(interp, argv[l], tlevel) '= TCL_0K) { return TCL_ERR0R, ) if (level == 0) { Tcl_DeleteTrace(interp, currentTrace) , ) else { FILE "fp, if (argc == 3) { if (Tcl_GetOpenFιle(interp, argv[2], 1, 1, ifp) '= TCL_OK) return TCL_ERROR, ) } else { TclOp.c Mon Mar 20 21:17:26 1995 2 fp = stderr, ) currentTrace = Tcl__CreateTrace (interp, level, Trace, fp) ) return TCL_OK; void Ns_InιtTcl (void) { char •library; char buf [0x100] if (interp ' = NULL) { Tcl_DeleteInterp(interp) , } interp = Tcl_CreateInterp( ) ; Tcl_SetVar2 (interp, "tcl_ιnteractιve' , NULL, 0" , TCL_GLOBAL_ONLY) , Tcl_CreateCommand(mterp, "ns_regιster_proc" , RegisterCmd, NULL, NULL) , Tcl_CreateCommand(interp, "ns_log", LogCmd, NULL, NULL), Tcl_CreateCommand(interp, "ns_httptιme", HttpTimeCmd, NULL, NULL) ; Tcl_Crea eCommand(interp, "ns_returnfιle" , ReturnFileCmd, NULL, NULL), Tcl_CreateCommand(interp, "ns_unlmk", RemoveFileCmd, NULL, NULL) ; Tcl_CreateCommand(interp, "ns_guesssuffix" , GuessSufflxCmd, NULL, NULL) Tcl_CreateCommand(interp, "ns_geturl", OpenUrlCmd, NULL, NULL); Tcl_CreateCommand(interp, "nε_tmpnam" , TmpNamCmd, NULL, NULL) ; Tcl_CreateCommand(interp, "ns_gethost" , GetHostCmd, NULL, NULL), Tcl_CreateCommand(interp, "ns_trace", TraceCmd, NULL, NULL); Tcl_CreateCommand(interp, "ns_wrιte", WriteCmd, NULL, NULL), Tcl_CreateCommand(mterp, "ns_headers" , HeadersCmd, NULL, NULL) , Tcl_CreateCommand(interp, "ns_εtrιphtml' , StripHtmlCmd, NULL, NULL); SetDBConn( ) ; library = Ns_LιbPath ( "tcl" , NULL, 0) , if (library == NULL) { die: LogError ( ) ; Ns_Fatal ( "Can' initialize Tcl ") ) ♦ifdef WIN32 Tcl_SetVar2 (interp, "NS", "onNt", "1", TCL_GLOBAL_ONLY) , ♦endif Tcl_SetVar2 (interp "NS" library", library, TCL_GLOBAL_ONLY) , Tcl_SetVar2 (interp "NS" pageroot" , me.pageroot, TCL_GLOBAL_ONLY) Tcl_SetVar2 (interp "NS" serverSelf", me.self, TCL_GLOBAL_ONLY) ; Tcl_SetVar2 (interp "NS" "serverName" me.name, TCL_GLOBAL_ONLY) ; Tcl_SetVar2 (interp "NS" "serverHost" me.hoεt, TCL_GLOBAL_ONLY) , sprintf (buf, "%d", me.port) ; Tcl_SetVar2 (interp, "NS", "serverPort buf, TCL_GLOBAL_ONL ) , sprintf (buf, "%d" , me.minorVersion) ; Tcl_SetVar2 (interp, "NS", "serverMinorVer buf, TCL_GLOBAL_ONLY) sprintf (buf, "%d", me.ma 3 orVersιon) ; Tcl_SetVar2 (mterp, "NS", "serverMa 3 orVer" , buf, TCL_GLOBAL_ONLY) ; Tcl_SetVar2 (interp, "NS", "verboseMode" , me. erboseMode "> "1' "0 TCL_GLOBAL_ONLY) ; if ( (Mι_Inιt(interp, library) '= TCL_OK) | | (Tcl_Eval (interp, init) '= TCL_OK)) { goto die; TclOp.c Mon Mar 20 21:17:26 1995 3 } TclOp(Ns_Conn "conn) { lastConn = conn; Tcl_SetVar2 ( terp, "NS" , "url", conn->request->url, TCL_GLOBAL_ONLY) ,- Tcl_SetVar2 (interp, "NS", "method' , conn->request->method, TCL_GLOBAL_ONLY) , SetDBConn() ; SetFor f"Form" , conn->form) , if (Tcl_Eval(interp, remit) '= TCL_OK) ( return LogError() , ) if (Tcl_Eval(mterp, conn->request->urlv[l] ) '= TCL_OK) { LogError() ; } lastConn = NULL; static void SetDBConn() { char buf[10]; extern void MiSetldlchar "id, MI_C0NNECTI0N "connection) extern MI_CONNECTION "connection, MiSetldfbuf, connection); Tcl_SetVar2(mterp, "NS", "dbconn", buf, TCL_GLOBAL_ONLY) , static void SetFormtchar "array. Form "form) { Tcl_UnsetVar(interp, array, 0), if (form == NULL) { return; ) for d = 0, l < form->NumFιelds, ++ι) { char "name; char 'value; name = form->fields[l] .name; value = form->fields[1] .value; if (name == NULL) { name = "" ; } if (value == NULL) { value = } Tcl_SetVar2 (interp, array, name, value, 0) static void LogError(void) TclOp.c Man Mar 20 21:17:26 1995 4 { char "errorInfo, errorlnfo = Tcl_GetVar( terp, "errorlnfo", TCL_GL0BAL_0NLY) , if (errorlnfo == NULL) ( errorlnfo = ιnterp->result, } Ns_Log(Error, "Tcl script failed:"); Nε_LogRaw(errorlnfo, strlen(errorlnfo) ) , static int RegisterCmd(ClientData dummy, Tcl_Interp " terp, int argc, char "argv) { int flags, if ((argc '= 4) it (argc '= 5)) ( Tcl_AppendResult(mterp, "wrong # of args should be N"' , argv(O), " prefix method procNa e ''flags'' , NULL), return TCL_ERROR, ) if (argc == 4) ( flags = 0, } else { if (Tcl_GetInt(interp, argv[4], tflags) '= TCL_OK) { return TCL_ERR0R; ) ) Ns_RegιsterOp(Ns_NewOp(argv[l] , argv[2], argv[3), TclOp, flags)), return TCL_OK; static int RemoveFileCmd(ClientData dummy, Tcl_Interp "mterp, int argc, char "argv) ( if ((argc '= 2) it (argc '= 3)) I badargs Tcl_AppendResul (interp, "wrong # of args should be N"', argv[0], " [-nocomplain] filenaune' , NULL), return TCL_ERROR, } if (argc == 2) { if (unlιnk(argv[l) ) '= 0) { Tcl_AppendResult(interp, "could not remove N"", argv[l] , "N"", NULL) , return TCL_ERROR; } ) else { if (strcmp(argv[l] , "-nocomplain") '= 0) { goto badargs, ) unlink(argv[2] ) , ) return TCL_OK, } static mt LogCmd(ClientData dummy, Tcl_Interp "interp, t argc, char "argv) { Ns_LogSeverιty severity, TclOp.c Mon Mar 2021:17:26 1995 if (argc '= 3) { Tcl_AppendResul (interp, "wrong # of args should be N" argv[0] , " severity message", NULL), return TCL_ERROR; } if (strcmp(argv[l] , "Notice") == 0) { severity = Notice, } else if (strcmp(argv[1] , "Warning") == 0) { severity = Warning, ) else if (strcmp(argv[l] , "Error") == 0) ( severity = Error; } else if (strcmp(argv[l] , "Fatal") == 0) { severity = Fatal,- } else if (strcmp(argv[1] , "Bug") == 0) { severity = Bug, ) else ( Tcl_AppendResult(mterp, "unknown serverity N'", argv[l], "N" should be one of Notice "Warning, Error, Fatal, or Bug , NULL), return TCL_ERROR, } Ns_Log(severity, argv[2]), return TCL_0K, static int HttpTimeCmd(ClientData dummy, Tcl_Interp "interp, int argc, char "argv) tιme_t "whenPtr, tιme_t when, if ((argc •= 1) it (argc '= 2)) ( Tcl_AppendResul (interp, "wrong # of args should be N"", argv[0], " 'time' , NULL), return TCL_ERROR, } if (argc == 1) { whenPtr = NULL, ) else ( int l. if (Tcl_GetInt(interp, argv(l) , ti) TCL_OK) { return TCL_ERROR, when = (tιme_t) l; whenPtr = twhen; ) Tcl_SetResult(interp, Ns_HttpTιme(whenPtr) , TCL_STATIC) , return TCL_OK, static int HeadersCmd(ClientData dummy, Tcl_Interp "interp, mt argc, char "argv) mt status, int len, if ((argc '= 2) tt (argc '= 4)) { Tcl_AppendResul (mterp, "wrong # of args should be V argv[0], " status 'type len'", NULL), return TCL_ERROR, TclOp.c Mon Mar 20 21:17:26 1995 6 } if (Tcl_GetInt (interp, argv[l] , istatus) '= TCL_OK) { return TCL_ERROR; } if (argc == 4) { if (Tcl_GetInt (interp, argv[3] , tlen) '= TCL_OK) { return TCL_ERROR, } ) Ns_RequιredHeaders (lastConn, status, "Script Results"), if (argc == 4) { Nε_TypeHeader (laεtConn, argv[2]), Ns_LengthHeader (lastConn, len) ; ) Ns_EndOfHeaders (lastConn) , return TCL OK, static mt RetumFileCmd(ClientData dummy, Tcl_Interp "interp, int argc, char "argv) { mt status, assert (lastConn '= NULL), if (argc '= 4) { Tcl_AppendResul (interp, "wrong ♦ of args should be N"", argv[0] , " status type filename", NULL), return TCL_ERROR; } if (Tcl_GetInt (interp, argv[l] , istatuε) ■ = TCL_OK) { return TCL_ERROR; } Ns_ReturnFιle(lastConn, status, argv[2], argv[3]) , return TCL_OK, static int GuessSuffixCmdtClientData dummy, Tcl_Interp " terp, int argc, char "argv) { if (argc '= 2) { Tcl_AppendResult (interp, "wrong ♦ of args should be N"' , argv[0] , " filename", NULL), return TCL_ERROR, } Tcl_SetResult (interp, guess_suffιx(argv[l] ) , TCL_STATIC) ; return TCL_OK; } static int TmpNamCmd(ClientData dummy, Tcl_Interp "mterp, int argc, char "argv) { char tmpfile [L_tmpnam] , /* * NB To be MT-safe, use a buffer on our stack even though it will be * copied by TCL */ if (tmpnamltmpfile) == NULL) { mterp->result = "could not generate temporary file name ", TclOp.c Mon Mar 20 21:17:26 1995 7 return TCL_ERROR, } Tcl_SetResult(interp, tmpfile, TCL_VOLATILE) , return TCL_OK, } static mt OpenUrlCmd(ClientData dummy, Tcl_Interp "interp, int argc, char "argv) { char "html; Form "headers, if ((argc '= 3) tt (argc '= 2)1 { Tcl_AppendResult(interp, "wrong # of args should be N"", argv[0], " url 'headersArrayVar' 1 , NULL), return TCL_ERROR, } if (argc == 2) { headers = NULL, ) else { headers = NewFor fNULL, NULL, 0), ) html = Ns_Url2Strιng(argv[l] , headers), if (html '= NULL) { if (headers '= NULL) { SetForm(argv[2] , headers), DelForm(headers) , } Tcl_SetResult(interp, html, TCL_VOLATILE) , ns_ ree(html) , ) return TCL OK, static int GetHostCmd(ClientData dummy, Tcl_Interp " terp, int argc, char "argv) { char "host; if (argc '= 2) ( Tcl_AppendResult(interp, "wrong ♦ of args- should be \ " , argv[0], " lpAddr , NULL), return TCL_ERROR, ) host = Ns_GetHostByAddr(argv[l] ) , if (host == NULL) { Tcl_AppendResult(interp, "Could not get hostname for argv[l] , NULL) , return TCL_ERR0R, } Tcl_SetResult(interp, host, TCL_VOLATILE) , return TCL OK, static int WriteCmd(ClientData dummy, Tcl_Interp "interp, int argc, char **argv) { asser (lastConn '= NULL), f (argc '= 2) ( Tcl_AppendResult(interp, "wrong ♦ of args should be N"", TclOp.c Mon Mar 20 21:17:26 1995 argv[0], " string", NULL) ; return TCL_ERROR; ) Ns_PutsConn(lastConn, argv[1] ) ; return TCL_OK; } void Ns_AccessLogOpen ( char " filenaune ) { accessLog = f open ( filenaune , "w" ) ,- if (accessLog == NULL) ( Ns_Fatal ( "Could not open access log file: %ε", ilename) ; } ) void Ns_AccessLog(Ns_Conn "conn) { if (accessLog '= NULL) { long minutesOff; char sign; char "dateti e; struct tm "tm; datetime = LogTι e(ttm) ,- ♦if defined! εvr4 ) | | defιned(hpux) minutesOff = timezone; ♦else minutesOff = tm->tm_gmtoff / 60; ♦endif if (minutesOff >= 0) ( sign = ' + ' ,- } else { minutesOff = -minutesOff; slgn = ' - ' ,- 1 SendChore( "ns_accesslog (%s) (- %s [%s %c%02d%02d] N"%sN" %d %d) " . conn->peerAddr, conn->authUser == NULL ? "-" : conn->authUser, datetime, sign, (int) (minutesOff / 60) , tint) (minutesOff % 60) , conn->request->lιne, conn->returnStatus, conn->returnLength) ,- void Def erPageUpdate ( char "url , char " type ) { i f Curl ' = ' / ' ) ( SendChore ( "nε_indexremote {%s} " , u 1) ; ) else { char "file; char normurl [_POSIX_PATH_MAX) file = Ns_PagePath(url , NULL, 0, normurl, sizeof (normurl ) - 1, TclOp.c Mon Mar 20 21:17:26 1995 9 NS_DιrfllesOK | NS_TopPagesOK, NULL) , die- Ns_Log(Error, "Couldn't defer page update"), return; } if (access(fιle, R_OK) •= 0) { goto die; ) if (STREQ(type, "tex /html") ) { SendChore( "ns_ιndex (%s) {%s)", normurl, file), } if (me.archiveMode) ( SendChore( "ns_archive {%s} {%s} {%s}", normurl, type, file), } DeferPageDelete (char *url) { SendChore! "ns_deleteιndex (%s)", url) ) void DeferChargelchar "user, int amount) { SendChore I "ns_charge {%s} {%d}", user, amount) ) SendDeferred (void) { if (me.choresPending) ( SendChore( "ns_flush" ) , me.choresPending = 0, ) ) SendChore(char *f t, ... ) { va_lιst ap; va_start(ap, fmt); vfprin f (me.choresFp, fmt, ap) va_end(ap) ; fprintf (me.choresFp, "Nn") , fflush(me.choresFp) ; me.choresPending = 1; void Chores (void) { ns_memory_valιdate_all ( ) , DM_Poll () , } TclCp.c Mon Mar 20 21:17:26 1995 10 void CheckChores(void) { if (wait(NULL) == me.choresPid) { Ns_Fatal("Index daemon died' ") } ) void OpenChores(void) { int fds[2], if (pιpe(fds) '= 0) { Ns_Fatal ("Could not create chores pipe " ) , } me choresPid = fork(), if (me choresPid < 0) { Ns_Fatal ("Could not fork chores daemon " ) } else if (me choresPid == 0) ( Tcl_DStrιng cmd, /* Ignore any keyboard interrupts from the controlling terminal */ setsidt ) ; close!fds[l] ) ; dup2(fds[0], 0), DM_ReOpenDB(NULL) , if (accessLog '= NULL) { Tcl_EnterFιle(interp, accessLog, TCL_FILE_WRITABLE) , Tcl_SetVar2(interp, "NS", "accessLog", ιnterp->result, TCL_GLOBAL_ONLY) ) Tcl_DStrιngInιt(icmd) , while (fgets(line, εizeof(line) , stdin) '= NULL) { Tcl__DStrιngAppend(tcmd, line, -1) if (Tcl_CommandComplete(cmd.string) ) { if (Tcl_Eval(interp, cmd string) '= TCL_OK) { LogErro () , ) Tcl_DStrιngTrunc(icmd, 0), } ) Ns_Log(Warning, "Chores got EOF on stdin'"), exιt(l) , ) else { if (accessLog '= NULL) { fclose(accessLog) , ) close(fds[0] ); Ns_Log(Notice, "Indexing daemon started, pid = %d" , me choresPid), me.choresFp = fdope (fds[1] , "w") ; signal(SIGCHLD, CheckChores) , static mt StripHtmlCmd(ClientData dummy, Tcl_Interp "interp, int argc, char "argv) { mt intag, char "ip. TclOp.c Mon Mar 20 21:17:26 1995 11 char "op, if (argc '= 2) { Tcl_AppendResul (interp, "wrong ♦ of args should be N' argv[0) , " page' , NULL) ,- return TCL_ERR0R; } ip = argv[1] ; op = ip; intag = 0; while ("ip '= 'NO') { if ("ip == '<') { intag = 1; } else if (intag it Cip == '>') ) { intag = 0, ) else if ( ' intag) { *op++ = "ip, ) ++ιp, } "op = 'NO' , Tcl_SetResult ( terp, argv[l], TCL_VOLATILE) , return TCL_OK, TypaChack. c Tua Mar 7 13 : 52 : 29 1995 1 ♦include "nsd. h " static char rcsιd[] = "Sid TypeCheck c,v 1 6 1995/03/07 21.52:41 doug Exp $"; ♦define STREQUAL(a,b) (Cta) == "(b)) ii (strcmp( (a) , (b) ) == 0)) ♦define TYPE_ERRMSG(value,name,type) ns_append_errorI"Value N"%sN" in column <I>%s</I> is not of type %s", (value), (name), (type)), static int NormalιzeTιmeInForm(Ns_Set "colvalues, char "field), static int NormalιzeDateInForm(Ns_Set "colvalueε, char "field) , static int NormalιzeTιmeStampInForm(Ns_Set "colvalues, char "field), static int DeNormalιzeTιmeInForm(Ns_Set "colvalueε, char "field, char "sqltimestr) , static int DeNormalιzeDateInForm(Ns_Set "colvalues, char "field, char "datestr) , static int DeNormalιzeTιmeStampInForm(Nε_Set "colvalues, char "field, char "timestampstr) , static char *NormallzeTime(char "time, char "ampm), static char "NormalizeDate(char "monthstr, char "daystr, char "yearstr), static char "MakeField (char "parti, char *part2), static void AppendFormSubFιeld(Nε_Set "form, char "parti, char *part2, char "value), static char *GetFormSubValue(Ns_Set 'form, char "parti, char *part2), static void DelFormSubFιeld(Ns_Set "form, char "parti, char *part2); static void DelFormFieldAndSubFields(Ns_Set "form, char "parti), static char "months[] = { "January", "February", "March", "April "May , 'June", "July" "August", "September", "October", "November", "December", NULL), /* Type checking stuff Returns either NS_FAIL or NS_OK For each field that is an invalid value, a message is printed via ns_append_error Handles real, double precision, integer, inti, charl, character(n) , boolean */ int Ns_TypeCheckValue (DM_TableInfo "tinfo, char "name, char "value) ( int index; char *type,- int bound; index = DM_ColumnInde (tinfo, naune), if (index < 0) { ns_append_error("Column %s does not exist in table %s", naune, DM_TableName(tinfo) ) , return NS_FAIL; } /* Assumes that database is preventing bogosity in the column_type and column_bound */ type = DM_ColumnValue(tinfo, index, "column_type" ) , bound = atoi(DM_ColumnValue(tinfo, index, "column_bound" ) ) , /* NB. null strings are treated like NULL DB values */ if (value == NULL || "value == 'NO') { return NS_OK; ) if (STREQUAL(type, "integer") | | STREQUAL( ype, "smallint") TypaCheck.c Tua Mar 7 13:52:29 1995 2 || STREQUAL(type, "intl")) { char "ptr; long numval = strtol (value, iptr, 10); if (ptr < value+strlen(value) ) { TYPE_ERRMSG(value,name,type) ; return NS_FAIL; } if (STREQUAL(type, "intl") tt ((numval < -128) | | (numval > 127))) { ns_append_error("Value N"%sN" in column <I>%s</I> is out of range (-128 tlt;= n tlt;= 127) Nn", value, naune) ; return NS_FAIL; ) } else if ISTREQUAL(type, "decimal") | | STREQUALItype, "numeric") II STREQUAL(type, Veal") I I STREQUAL(type, "double precision" ) ) { char "ptr; strtodlvalue, tptr) ; if (ptr < value+strlen(value) ) { TYPE_ERRMSG(value,name,type) • return NS_FAIL; ) ) else if (STREQUAL! ype, "boolean") ) { if (STREQUAL(value, "t") || (STREQUAL(value, "f") ) ) { return NS_OK; } else { TYPE_ERRMSG(value,name, type) ; return NS_FAIL; ) ) else if (STREQUAL(type, "character") | | STREQUAL(type, "char") I I STREQUAL(type, "varchar")) { if ( (bound != 0) ii (strlen(value) > bound)) { ns_append_error("Value N"%sN" in column <I>%s</I> is longer than %d characters Nn" value, name, bound); return NS_FAIL; ) ) else if (STREQUALItype, "charl") ) { if Istrlen(value) > 1) { ns_append_error("Value N"%sN" in column <I>%s</I> is more than 1 characterNn", value, name) ; return NS_FAIL; } } return NS_OK; ) int Ns_TypeCheckSet (DM_TableInfo "tinfo, Nε_Set "colvalues) ( int i,- int retcode = NS_OK; assert(tinfo != NULL); assert(colvalues != NULL); for (i=0; i<Ns_SetSize(colvalues) ; i++) { if (Ns_TypeCheckValue(tinfo, Ns_SetKe (colvalues,i) , Nε_SetValue(colvalues,i) ) == NS_FAIL) { retcode = NS_FAIL; TypaCheck.c Tua Mar 7 13 : 52 :29 1995 } } return retcode; ) /* Puts together the pieces of dates, times, and timestamps. Delete from the form any Colnames that have .NULL "t" returns NS_FAIL on anything weird. */ int Ns_NormalιzeColValues(DM_TableInfo "tinfo, Ns_Set "colvalues) { εtatic char name[128]; /* This is ok, because the function is tail-recursive */ assert (tinfo '= NULL) ; assert (colvalueε '= NULL), for (ι=0; ι<Ns_SetSιze(colvalues) , ι++) { char "ext, "fullname, "value, fullname = Ns_SetKey(colvalueε, I ) , value = Nε_SetValue (colvalues, I) ; ext = strchr (fullname, * (NS_FORM_SEPARATOR) ) , if (ext '= NULL) { int len = ext-fullneune, char *type; int index; strncpy(name, fullname, len) ,- naune[len] = ' NO' ; ext++,- index = DM_ColumnIndex(tmfo,name) ; if (index == -1) { return NS_FAIL; } type = DM_ColumnType (tinfo, index) , if (type == NULL) { return NS_FAIL, } if (STREQUAL(ext, "NULL") ) { if (STREQUAL!value, "t") ) { DelFormFieldAndSubFields (colvalues,name) , return Ns_NormalιzeColValues (tinfo, colvalues) , ) else if {STREQUAL!value, "f") ) { DelFormFieldlcolvalues, fullname) ,- return Ns_NormalιzeColValues (tmfo, colvalueε) ; } else { return NS_FAIL, } } else if (STREQUAL(type, "date") it (STREQUAL!ex ,NS_FORM_MONTH_KEY) I I STREQUAL!ext,NS_FORM_DAY_KEY) J l STREQUA (ext,NS_FORM_YEAR_KEY) ) ) { if (NormalizeDatelnForm(colvalues, name) == NS_OK) { return Ns_NormalιzeColValues (t fo,colvalues) ; } else { return NS_FAIL; } } else if (STREQUAL(type, "timestamp" ) it (STREQUAL(ext,NS_FORM_MONTH_KEY) I I STREQUAL(ext,NS_FORM_DAY_KEY) | | STREQUAL(ext,NS_FORM_YEAR_KEY) I I STREQUAL!ext,NS_FORM_TIME_KEY) j | STREQUAL(ext, S_FORM_AMPM_KEY) ) ) { TypeChack.c Tua Mar 7 13:52:29 1995 4 if (NormalizeTimeStampInForm!colvalues,name) == NS_0K) { return Ns_NormalιzeColValuesItinfo,colvalues) ; } else { return NS_FAIL, ) } else if (STREQUAL(type, "time") it (STREQUA (ex ,NS_FORM_TIME_KEY) | | STREQUAL(ext,NΞ_FORM_AMPM_KEY) ) ) ( if (NormalιzeTιmeInForm(colvalues, name) == NS_OK) ( return Ns_NormalιzeColValues (tinfo,colvalues) ; ) else { return NS_FAIL; ) } else { return NS_FAIL; ) } } return NS_OK; ) /* Splits out dates, times, and timestamps, Counts on DeNormalιze*InForm removing 3 ust the one field. */ Ns_DeNormalιzeColValues(DM_TableInfo "tinfo, Ns_Set "colvalues) { int ι = 0, while (ι<Ns_SetSιze(colvalues) ) { char "name = Ns_SetKey(colvalues, I) ; char "value = Ns_SetValue(colvalues,I) ,- if ( (value == NULL) || (strchr(name, *(NS_FORM_SEPARATOR) ) '= NULL)) { ι++; ) else { mt index; char "type; dex = DM_ColumnIndex(t fo,name) ; * if (index == -1) { return NS_FAIL; } AppendFormSubFιeld(colvalues,name, "NULL" , "f" ) ; type = DM_ColumnType(tinfo, index) ; if (type == NULL) { return NS_FAIL; ) lf (STREQUAL(type, "da.te") ) { if (DeNormalιzeDateInForm(colvalues,name,value) == NS_FAIL) { return NS_FAIL; ) DelFormFieldlcolvalues,name) ; } else if (STREQUAL(type, "time") ) { if (DeNormalizeTimelnFormlcolvalues,name, alue) == NS_FAIL) { return NS_FAIL; } DelFormFιeld(colvalues,name) ; } else if (STREQUAL(type, "timestamp" ) ) { if (DeNormallzeTimeStampInFormlcolvalues,name,value) == NS_FAIL) { return NS_FAIL; } DelFormField l colvalues , naune ) , ) else { ι + + ; TypaCback. c Tua Mar 7 13 : 52 : 29 1995 5 } } ) return NS_OK , } /* Just adds the proper subfields, does not remove the old one, so that DeNormalizeTimeStamp can call this */ static int DeNormalizeTimelnForm (Ns_Set "colvalues, char "field, char "sqltimeεtr) { mt num, hours, minutes, seconds, char timestr[16]; char "aunpm; num = sscanf(sqltimestr, "%d-%d-%d" ,thours,tminutes,tseconds) , if ( (num '= 3) I I (minutes < 0) | | (minutes > 59) I I (seconds < 0) j j (seconds > 61)) { return NULL, ) if (hours == 0) { hours = 12, ampm = NS_FORM_AM; ) else if ((hours > 0) tt (hours < 12)) { ampm = NS_F0RM_AM, } else if (hours == 12) { ampm = NS_FORM_PM, ) else if ((hours > 12) tt (hours < 24)) { ampm = NS_FORM_PM; hours-=12; ) else { return NS_FAIL, ) sprintf(timestr, "%d:%02d-%02d" .hours, minutes, seconds), AppendFormSubFιeld(colvalues, field, S_FORM_TIME_KEY.timestr) , AppendFormSubFιeld(colvalues, fιeld,NS_FORM_AMPM_KEY,ampm) , return NS_OK, } static int DeNormalizeDatelnForm (Ns_Set "colvalues, char "field, char "datestr) { mt year, month, day, num; char yearstr[5], daystr[3], char "monthstr, num = sscanf(datestr, "%d-%d-%d", iyear, tmonth, tday) , if ( (num '= 3) I I (year < 0) | | (year > 9999) I I (month < 0) | | (month > 12) j I (day < 1) | | (day > 3D) { return NS_FAIL; ) monthstr = months(month-1] , sprintf(daystr, "%d' , day), TypeCheck.c Tua Mar 7 13:52:29 1995 6 sprintf(yearstr, "%d" ,year) , AppendFormSubField(colvalues,fιeld,NS_FORM_YEAR_KEY,yearstr) , AppendFormSubField(colvalues, fιeld,NS_FORM_DAY_KEY,daystr) AppendFormSubField(colvalues, field,NS_FORM_MONTH_KEY,monthstr) return NS OK, } static t DeNormalizeTimeStampInForm (Ns_Set "colvalues, char "field, char "timestampstr) { char tιmestr[32], char datestr[32] , int num, if (strlen(timestampstr) > 31) { return NS_FAIL, } num = sscanf (timestampstr,' %s %s' ,datestr, timestr) if (num '= 2) ( return NS_FAIL, } if (DeNormalιzeTιmeInForm(colvalues, field, timestr) == NS_FAIL) { return NS_FAIL, ) if (DeNormalιzeDateInForm(colvalues, field, datestr) == NS_FAIL) ( return NS_FAIL, } return NS_OK, ) static char " MakeField (char "parti, char *part2) { static char fιeld[128], sprintf(field, "%s%s%s ' ,parti, S_FORM_SEPARATOR,part2) return field, ) static void AppendFormSubField(Ns_Set "form, char "parti, char *part2, char "value) { AppendFormField(form, MakeField(parti,part2) ,value, 0,0), ) static char * GetFormSubValue(Ns_Set "form, char "parti, char *part2) { return GetFormValue(form,MakeField(parti,part2) ) , } static void DelFormSubFιeld(Ns_Set "form, char "parti, char *part2) { DelFor Field(form,MakeField(parti,part2) ) , } static void DelFormFieldAndSubFields(Ns_Set "form, char "parti) ( int l, TypaChack. c Tua Mar 7 13 : 52 : 29 1995 1=0; while (l < form->NumFιelds) { char "name = form->fields[l] .name, if (strncmp(name, parti, strlen(parti) ) == 0) DelFormField(form,naune) , ) else { ) static char * NormalizeTimelchar "time, char "ampm) { static char hold[128], mt hours, minutes, seconds, num, if ((time == NULL) | | (ampm == NULL)) { return NULL; } seconds = 0; num = sscanf(time, "%d:%d:%d" ,thours,tmmutes,tseconds) , if ( (num < 2) | | (num > 3) || (hours < 1) || (hours > 12) || (minutes < 0) || (minutes > 59) || (seconds < 0) || (seconds > 61)) { return NULL; ) lf (STREQUAL(ampm,NS_FORM_AM) ) { if (hours == 12) { hours = 0, } ) else if (STREQUAL!ampm,NS_FORM_PM) ii (hours '= 12)) { hours+=12; } else { return NULL, ) sprintf(hold, "%02d:%02d:%02d",hours,minutes,seconds) , return hold; static int NormalιzeTιmeInForm(Ns_Set "colvalues, char "field) { char *tιme, *a_mpm, 'timestr; time = GetFormSubValue(colvalueε,field,NS_FORM_TIME_KEY) , ampm = GetFormSubValue(colvalues, field,NS_FORM_AMPM_KEY) , timestr = NormalizeTime(time,a_mpm) ; if (timestr -» NULL) { ns_append_error("Invalid time specification"), return NS_FAIL; } DelFormSubField(colvalues,field, S_FORM_TIME_KEY) ; DelFormSubField(colvalues, field,NS_FORM_AMPM_KEY) ; AppendFormField(colvalues, field,timestr,0,0), return NS_OK; ) static char * TypaCheck.c Tua Mar 7 13:52:29 1995 β NormalizeDate(char *monthstr, char *daystr, char *yearstr) { static char hold[128] , int month = 0, int day = atoi(daystr) , int year = atoi (yearεtr) , mt l, for (ι=0; ι<12, ι++) { if (STREQUAHmonths[I] .monthstr) ) { month = l+l, break, } } if ((month < 1) | | (month > 12) I I (day < 1) j | (day > 31) I j (year < D) { return NULL, ) sprintf(hold, "%04d-%02d-%02d ',year, month, day), return hold, ) static int NormalιzeDateInForm(Ns_Set *colvalues, char "field) { char "month, "day, "year, "datestr, month = GetFormSubValue(colvalues, field,NS_FORM_MONTH_KEY) day = GetFormSubValue(colvalues, field,NS_FORM_DAY_KEY) , year = GetFormSubValue(colvalues, field,NS_FORM_YEAR_KEY) datestr = NormalizeDate(month, day, year), if (datestr == NULL) { ns_append_error( "Invalid date specification") return NS_FAIL, ) DelFormSubField(colvalues, field,NS_FORM_MONTH_KEY) DelFormSubField(colvalueε, field,NS_FORM_DAY_KE ) , DelFormSubField(colvalues, field,NS_FORM_YEAR_KE ) , AppendFormField(colvalues, field,datestr,0,0), return NS OK, ) static int NormalιzeTιmeStampInForm(Ns_Set "colvalueε, char "field) ( char timestampstr[128] , char "month, "day, "year, "time, "ampm "timestr "datestr, month = GetFormSubValue(colvalues, field,NS_FORM_MONTH_KE ) , day = GetFormSubValue(colvalues, field,NS_FORM_DAY_KEY) , year = GetFormSubValue(colvalues, field, S_FORM_YEAR_KEY) , time = GetFormSubValue(colvalues, field, S_FORM_TIME_KEY) ampm = GetFormSubValue(colvalues, field,NS_FORM_AMPM_KEY) , timestr = NormalizeTime(time, ampm), datestr = NormalizeDate(month day, year), TypaCback.c Tua Mar 7 13:52:29 1995 9 if ((timestr == NULL) || (datestr == NULL)) { ns_append_error ( "Invalid timestamp specification") return NS_FAIL, } sprintf(timestampstr, "%s %s",datestr, timestr), DelFormSubField(colvalueε, field, S_FORM_MONTH_KEY) , DelFormSubField(colvalues, field,NS_FORM_DAY_KEY) , DelFormSubField(colvalues, field,NS_FORM_YEAR_KEY) , DelFormSubFiel (colvalues. fιeld,NS_FORM_TIME_KEY) , DelFormSubField(colvalues, field,NS_FORK_AMPM_KEY> , AppendFormField(colvalues, field,timeεtampεtr,0,0), return NS_OK, hllita.c Mon Mar 6 14 : 11: 59 1995 1 / * hilite . c General purpose hiliting functions, used to generate query terms as well as hilite an html page Does NOT include the GetHilitedPage function ♦include "nsd.h" ♦include "nlp.h" static char rcsιd[] = "SHeader /current/src/nsd/RCS/hilite.c,v 1 7 1995/03/03 18 11 44 do ug Exp $",- ♦define TOKTYPE_EOF -1 ♦define TOKTYPE_WORD 1 ♦define TOKTYPE_TAG 2 ♦define TOKTYPE_OTHER 3 ♦define StartsAnchor(tok) ( (strlen(tok) >= 3) tt ( (strncmp( (tok) , "<A ",3) == 0) || (strncm p((tok),"<a ",3) == 0) | | STREQ( (tok) , "<A>" ) || STREQt (tok) , "<a>") ) ) ♦define EndsAnchorltok) (STREQ( (tok) , "</A>") || (STREQ( (tok) ,' </a>' )) ) char "ConvertTerms (char "terms, mt "argc), int ReadToken(char "ppos, char "tokbuf, mt maxtoklen) ,- int Member (char "thing, char "parts, int numparts) ; char "HiliteURL (char "origurl, char "terms, char "collection) { char "morelikethisurl = BuildMoreLikeThisURL(origurl, collection); char "baseurl = Ns_AbsoluteUrl (origurl) ; char "termparts; mt numterms,- char tokbuf[256] ,- char stembuf[64] ; int toktype; mt inAnchor = 0; int msertBaseTag = 1, mt lnsertOπgLink = 1, int insertFirstStrong = 1, int insertFirstMarker = 0, Form "headers = NULL; char "pagebody; char "pagebodypoε, NS..DSTRING ds; pagebody = Ns_Url2Strιng(origurl, headers), if (pagebody == NULL) { ns_append_error ("Could not open URL %s for hiliting" ,origurl) ,- return NULL; } pagebodypos = pagebody; ns_dstnng_ιnιt(ids) , termparts = ConvertTerms(terms,tnumterms) ; while (((toktype = ReadToken(tpagebodypos, tokbuf, sizeof(tokbu )) ) '= T0KTYPE_E0F) it insertBaseTag) { hilitβ.c Mon Mar 6 14:11:59 1995 /* If you've got a head that doesn't contain a base tag, insert one If it does contain a base tag, then move on. */ if (ttoktype == TOKTYPE_TAG) tt ( (strcmpf okbuf, "<HEAD>") == 0) || (strcmp(tokbuf, "<head>" ) == 0))) { ns_dstrιng_append(ids,tokbuf) , while (((toktype = ReadToken(tpagebodypos, tokbuf, sizeof(tokbuf) ) ) '= TOKTYPE_EOF) ) { if ( (strcmp(tokbuf, "</HEAD>" ) == 0) || (strcmp(tokbuf, "</head>" ) == 0)) { if (insertBaseTag) { ns_dstπng_varappend(tds, "<BASE HREF=" ,baseurl, ">" ,NULL) , insertBaseTag = 0, } ns_dstrιng_append(tdε, okbuf) , break; } if (insertBaseTag tt (strlen (tokbuf) >= 6) it ( (strncmp(tokbuf, "<BASE ",6) == 0) || (strncmp(tokbuf, "<base ",6) == 0))) ( insertBaseTag = 0; } ns_dstπng_append(ids,tokbuf) ; /* If there is a BASE, 3 ust move on } else if ((strlen (tokbuf) >= 6) it strncmp(tokbuf "<BASE " ,6) == 0) { insertBaseTag = 0, ns_dstrιng_append(ids,tokbuf) , } else if ((toktype == TOKTYPE_TAG) tt (strcmp (tokbuf,"<HTML>") '= 0) ii (strcmp (tokbuf, "<html>") '= 0)) { /* If you get a tag other than HEAD, HTML, or BASE then assume that there is no head, insert the base and move on */ ns_dstrιng_varappend(ids, "<BASE HREF=" ,baseurl, ">",NULD ; ns_dstrιng_append(ids,tokbuf) ; insertBaseTag = 0; } else ( ns_dstrιng_append(ids,tokbuf) , /* Highlight the terms, a_nd insert link to original */ while ((toktype = ReadToken(tpagebodypos, tokbuf, εizeof(tokbuf)) ) ι= TOKTYPE__EOF) ( if ((toktype == TOKTYPE_WORD) ii /* stem is one of termparts */ (Member (StemWord(tokbuf, stembuf, sizeof (stembu )) , termparts, numterms))) { if (insertFirstStrong) { hilitβ.c Mon Mar 6 14:11:59 1995 if (inAnchor) { ns_dstrιng_varappend(tds, "<STRONG>" ,tokbuf, "</STRONG->",NULL) , insertFirstMarker = 1; } else { ns_dstrιng_varappend(tdε, "<STRONGxA NAME= " " , NS_FIRSTTERM, "\">" , tokbuf, "</Ax/STRONG>" , NULL) ; msertFirstStrong = 0; ) } else { ns_dstr ng_varappend(tds, "<STRONG>" ,tokbuf, "</STR0NG>" .NULL) ) } else if (insertOrigLink tt ( (strcmpItokbuf, "</HTML>") == 0) | | (εtrcmpltokbuf, "</html>") == 0) j| (strcmp(tokbuf, "</B0DY>") == 0) || (strcmp(tokbuf, "</body>") == 0))) ( ns_dstπng_varappend(tds, " n<BR>Vιew the <A HREF=" , baseurl, ".-original document</A> " .NULL), ns_dstrmg_varappend(tds, " n<BR>Vιew <A HREF=", morelikethisurl, ">documents</A> like this one.Nn", NULL), insertOrigLink = 0; ns_dstrιng_append(ids, okbuf) , } else { ns_dstrmg_append(ids,tokbuf) , ) if (StartsAnchor(tokbuf) ) { inAnchor = 1; } i f ( EndsAnchor ( tokbuf ) ) { inAnchor = 0 , i f ( insertFirstMarker ) { ns_dstnng_varappend (ids , "<A NAME= " " , NS_FIRSTTERM, "N"x/A>" .NULL) , insertFirstMarker = 0; } if (insertOrigLink) { ns_dstrιng_varappend(tds, "Nn<BR>Vιew the <A HREF=", baseurl, ">orιgιnal document</A> ",NULD; ns_dstrιng_varappend(tds, "Nn<BR>Vιew <A HREF=", morelikethisurl, ">documents</A> like this one.Nn", NULL) ) /* Free termparts */ ns_free(termparts[0) ) , ns_frεe( ermparts) ; nε_free(pagebody) ; return ns_dstrιng_movestnng(ids) ; /* Add error checking */ char *"ConvertTerms (char "terms, int "argc) { char "dup; char "sp; int k; char "argv; hilite.c Mon Mar 6 14:11:59 1995 dup = ns_strdup (terms) , for (k=0, sp=dup, ("sp '= 'NO') , sp++) { if ("sp == ' , ') { k++, } ) "argc = 1+k, argv = (char **)ns_calloc ("argc + 1, sizeof (char *)) for (k = 0, sp=dup, ("sp '= 'NO'), k++) { argv[k] = sp, while (Csp ' ='N0') it ("sp ' = ', ') ) { sp++, ) if ("sp == ' . ') ( "sp = 'NO' , sp++, if (argv[0] == NULL) "argc return argv, int Member (char "thing, char *"parts, int numparts ) { int l , for (ι=0, Knumparts, ι++) ( if (strcmp(thing,parts [I] ) == 0) ( return 1 , ) ) return 0 , ) /* Tokens are sequences of alpha characters or sequences of anything else No characters are lost */ int ReadToken(char "psrcstr, char "tokbuf, int maxtoklen) ( char c, char "pos = tokbuf, int toktype, c = "psrcstr; ( "psrcstr) ++, if (c =- 'NO' ) return TOKTYPE_EOF, "pos = c, pos++, if (isalpha (c) ) toktype = TOKTYPE_WORD, else if (c == '< ' ) toktype = TOKTYPE_TAG, else toktype = T0KTYPE_0THER, while ( ( (pos - tokbuf) < maxtoklen) it ( (c=**psrcstr) '= ' NO' ) ) { hilite.c Mon Mar 6 14:11:59 1995 5 ("psrcstr)++; if (((toktype == T0KTYPE_W0RD) it isalpha(c) ) | | ((toktype == TOKTYPE_OTHER) tt !isalpha(c) tt (c != '<')) || ((toktype == TOKTYPE_TAG) tt C(pos-l) != '>'))) { "pos = c; pos++; ) else { /* put the char just read back */ ("psrcstr)--; break; ) ) return toktype; /* Pull out all non stop words, εtem them, and comma separate them with no spaces so they can be jammed onto the end of the URL. Allocates a new string (that must later be freed!) Assumes that all stemε are shorter than the actual word. */ char *Query2Terms (char "query) { char *terms,- char "pos; char tokbuf[64] ; char stembuf[64] ,- int i,- /* Allocate 2 more bytes for the potential comma and the 'NO' * pos = (terms = (char *) ns_malloc(strlen(query)+2) ) ,- while ("query != 'NO') { if (isalpha!"query) ) { i = 0; while (("query != 'NO') tt (isalpha ("query)) tt (i+l<sizeof (tokbuf)) ) { tokbuf[i]=tolower("query) ; i++; query++; } tokbu [i]='NO' ; if ( iisStopWordt okbuf) ) { StemWord(tokbuf, stembuf,sizeof(stembuf) ) ; strcpy(pos,stembuf) ; pos += strlen(pos); "pos = pos++; "pos = 'NO' ; ) } else query++; } if (pos == terms) { /" No terms found */ "terms = 'NO' ; ) else *(pos-l) = 'NO'.- return terms; hilite.c Mon Mar 6 14:11:59 1995 6 /* Read just the text from the html, stem the words, and return as many unique non-stopwords as possible. the return value is a static. */ char *Nε_Url2Queryεtr (char *url) { static char querystr[128] ; /* DANGER Will Robinson! these urls get too big! */ char "querystrpos = querystr; char "querystrend = querystr + sizeof(querystr) ; int toktype; char tokbuf[256] ; char stembuf[64],- Form "headers = NULL; char "pagebody; char "pagebodypos; assert(url !=NULL) ; memset(querystr, 'NO', sizeof (querystr)) ,- pagebody = Ns__Url2String(url, headers); if (pagebody == NULL) { ns_append_error ("Could not open URL %s",url); return NULL; } pagebodypos = pagebody; while ((toktype = ReadToken(tpagebodypos, tokbuf, sizeof (tokbuf)) ) != T0KTYPE_E0F) { if ((toktype == T0KTYPE_W0RD) ii ( !isStopWord( okbuf)) ) { StemWord(tokbuf,stembuf,sizeof(stembuf) ) ; if (εtrstr(querystr,stembuf) == NULL) ( /* stem is not already in querystr, add it. */ if ( (strlen(stembuf) + 2) > (querystrend - querystrpos)) { /* querystr is full, return it */ return querystr; } else { strcpy(querystrpos,stembuf) ; querystrpos+=strlen(stembuf) ; "querystrpos = ' ' ; querystrpos++; } } } ) return querystr; a-arαepaga .c Mon Fab 27 18 :26 : 19 1995 1 /* * * NAME : ** Ns_MergePage - Merge a row of data into an update page. _• ** SYNOPSIS ** ♦include "ns.h" ** HtmlPage 'page; ** page = Ns_MergePage(char *page, Form *row) ** ** KillHTMLPage(page) ; * * " DESCRIPTION: ** Ns_MergePage returns a new HTML page build from the page ** string {page) with the data from {row) merged in. * » ** RETURN VALUE: ** pointer to an HTML page or NULL for error. Be εure to ** KillHTMLPage() the page when no longer needed. ** GLOBALS ACCESSED ** None # * " ERRORS: " Several are possible. static char rcsid[] = "SHeader: /current/src/nsd/RCS/mergepage.c,v 1.3 1995/02/28 02:2 6:17 jimbo Exp $" ; ♦include "nsd.h" ♦define BUFSIZE 254 typedef enum { TEXT, RADIO, CHECK } input_t; static int EditInputTag(char "op, NS_DSTRING "text, Form "values); static int EditSelectTa (char "op, NS_DSTRING "text, Form "values); static int EditFormtPara "para. Form "values) ,- static char "GetFieldNameForTagName(Form "values, char "tag); static char "GetValueForTagName(Form "values, char "tag) ,- static void AddOptionTag(NS_DSTRING "pds, char "string, int isselected); HtmlPage * Ns_MergePage(char 'html, Form 'row) { HtmlPage "page; assert(html != NULL); assert(row != NULL) ; page = FillHtmlPage(NULL, parse_string, thtml) ; if (page != NULL) { Para 'formp; /* * Find and edit any <FORM> paragraphs */ for (formp = page->first; formp != NULL;) { if ( (formp->tag == FORM_TAG) ii (EditForm(formp, row) != NS_OK) ) { KillHtmlPage(page) ,- struct rlimit rl; nε_memory_valιdate(NS_OFF) /* * Set hard wired defaults. */ me.naune = "NaviServer"; me.ma 3 orVersιon = 0; me.minorVersion = 1; me.foregroundMode = 0; me.shutdownPending = 0,- me.restartPendmg = 0, me.resultsPend g = 0; me.choresFp = NULL; me.choresPid = 0; me.uid = 0, /* * Set environment variable defaults */ gotuid = 0,- p = getenv("NS_UID" ) ; if (p '= NULL) { ++gotuιd; } p = getenv("NS_USERNAME" ) ,- if (p '= NULL) ( me.uid = Ns_GetUιd(p) ,- ++gotuιd; } if (gotuid > 1) { fprintf(stderr, "Only one of NS_UID or NS_USERNAME allowed Nn' ) p = getenv("NS_VERBOSE") ; if (p == NULL) { me.verboseMode = 0; ) else ( me.verboseMode = 1; p = getenv("NS_CHROOT") ; if (p == NULL) ( me.chrootMode = 0; } else { me.chrootMode = 1; } p = getenv("NS_VERSIONING") , if (p == NULL) { me.archiveMode = 0; ) na . c Tua Mar 21 20 : 32 : 37 1995 else { me.archiveMode = 1; } p = getenv("NS_ACCOUNTING" ) ; if (p == NULL) { me.chargeMode = 0,- } else { me.chargeMode = 1,- } me.dbuser = getenv!"NS_DBUSER") ; if (me.dbuser == NULL) { me.dbuser = "nsadmin"; ) me.dbpassword = getenv("NS_DBPASSWORD" ) if (me.dbpassword == NULL) ( me.dbpassword = "",- ) me.dbname = getenv("NS_DBNAME" ) ; if (me.dbname == NULL) { me.dbname = "ns"; ) me.dbserver = getenv( "NS_DBSERVER") ,- if (me.dbserver == NULL) ( me.dbserver = "ns"; p = getenv("NS_PORT") .- if (p != NULL) { me.port = atoi(p); } else { if (geteuidO == 0) ( me.port = 80; } else { me.port = 0; } } p = getenv("NS_TIMEOUT") ; if (p == NULL) { me.selectTimeout = 60; } else { me.selectTimeout = atoi(p); ) me.directoryFile = getenv("NS_DIRECTORYFILE" ) if (me.directoryFile == NULL) ( me.directoryFile = "index.html"; ) me.userMapdir = getenv("NS_USERMAPDIR") ; me.accessLog = getenv("NS_ACCESSLOG") ; me.errorLog = getenv("NS_ERRORLOG" ) ; me.cgiPrefix = getenvl"NS_CGIPREFIX") ; me.cgiDirectory = getenvl"NS_CGIDIRECTORY" ) ; me.pageroot = getenvl"NS_PAGEROOT" ) ; nad.c Tua Mar 21 20:32:37 1995 me home = getenv! "NS_HOME" ) , me.host = getenv( "NS_HOSTNAME" ) , me.self = getenv( "NS_HOSTLOCATION" 1 , /* * Override the defaults with command line arguments */ gotuid = 0, while ( (option = getopt(argc, argv, "RvAVhfN. :H.d • .l u.c C r e 1 p t S:D:U P F ")) '= -1) { switch (option) ( case 'l' . ++gotuιd, me.uid = atoi(optarg) , break, case 'u' ++gotuιd, me.uid = Ns_GetUιd(optarg) , break, case 'v' me.verboseMode = 1, break, case 'f' me.foregroundMode = 1, break, case 'd' me.directoryFile = optarg, break, case 'm' me.userMapdir = optarg, break, case 'c' me.cgiPref x = optarg, break, case 'C me cgiDirectory = optarg, break, case 'R' me chrootMode = 1, break, case 'r' me.pageroot = optarg, break, case 'S' me.dbserver = optarg, break, case 'U' . me.dbuser = optarg, break,- case 'P' : me.dbpassword = optarg, break, case 'D' me dbnaune = optarg break, case ' 1 ' me.accessLog = optarg, break; case 'e' me.errorLog = optarg, break, case 'p' me port = atoi (optarg) nad.c Tua Mar 21 20:32:37 1995 5 break,- case 'V . me.archiveMode = 1; break; case 'A' me.chargeMode = 1, break; case 't' : me.selectTimeout = atoi(optarg) , break; case 'H' me.home = optarg, break; case 'N' me.host = optarg, break, case 'L' me.self = optarg; break; case 'F' . if (getrlιmιt(RLIMIT_NOFILE, tri) '= 0) ( perror( "Could not check for open files limit ' ), rl.rlιm_cur = atoi (optarg) ,- if (rl.rlιm_cur > rl.rlιm_max) { fprintf (stderr, "Can only open up to %d filesNn' , r1. r1ιm_max) exιt(l) ; } if (setrlimit (RLIMIT_NOFILE, tri) '= 0) { perror ( "Could not εet open files limit ") , exi (1) , } break,- default • badargs . usage(argc, argv) , break, ) ) /* * Verify the options and flags */ if (optind < argc) ( fprintf (stderr, "%s takes no arguments after flags -Nn", argv[0] ) ; goto badargs, ) f (gotuid > 1) { fprintf (stderr, "Only one of -I or -u allowed. n" ) , goto badargs,- ) if (gotuid it (geteuidO '= 0)) ( fprintf (εtderr, "No privilege to change user ld.Nn") , if (me.chrootMode ii (geteuidO '= 0)1 ( fprintf (stderr, "No privilege to chroot \n") nad.c Tua Mar 21 20 : 32 : 37 1995 6 exit ( l ) ; } if ((geteuidO == 0) it igotuid tt ime.chrootMode) { fprintf (stderr, "Warning: Running as root without a chroot is insecure. Nn" ) } /* * Identify this server. */ if (me.host == NULL) { char hostname[255] ; struct hostent *he; if ( (gethostname(hostname, sizeof (hostname) 1 '= 0) | | ((he = gethostbyname(hostname) ) == NULL)) { fprintf(stderr, "Could not determine local hostnameNn. ") ; badhost: fprintf(stderr, "Please see the Naviserver Installation Guide " " or further information. Nn" ) ,- exit(l) ; ) if (strchr(he->h_name, '.') == NULL) ( fprintf(stderr, "The local hostname N"%sN" does not appear to beNn" "a fully qualified Internet domainname. Nn" , he->h_name) ; goto badhost; ) me.host = strdup(he->h_name) ; /* * Verify NS_HOME exists. */ if (me.home == NULL) { me.home = Ns_GetUserHomeI "nsadmin" ) ; if Ime.home != NULL) ( me.home = strdup(me.home) ; } else { me.home = "/usr/local/ns"; ) } if ( !Ns_DιrReadable(me.home) ) ( fprintf(stderr, "Can't access NS_HOME directory: %sNn", me.home) exιt(l) ; ) /* * Read the Illustra MiParams file before a posεible chroot. */ if (getenv(MI_SYSPARAMS) == NULL) { char "dbconf; Char buf[_POSIX_PATH_MAX + εizeof(MI_SYSPARAMS) + 2] dbconf = getenv("NS_DBCONFIG" ) ; if (dbconf == NULL) { dbconf = Ns_LibPath( "nsdb.conf" .NULL,0) ,- if (dbconf == NULL) { fprintf Iεtderr, "Can' build Nε_LibPathNn" ) ,- exitll) ; nad.c Tua Mar 2120:32:37 1995 7 ) sprintf(buf, "%s=%s' , MI_SYSPARAMS, dbconf), putenvlbuf) ,- J if (mι_getsysparam(me.dbserver, "MI_HOST") == NULL) { fprintf(stderr, "Can't contact database server. %sNn" , me.dbserver) exιt(l) ,- } /* * Aquire our port before the setuid because it may be privileged. */ if (Ns_BιndPort(me.port) '= NS_0K) { fprintf(stderr, "Could not bind port- %dNn", me.port); exιt(l) ; /* * Open the log files before doing a chroot or setuid */ if (me. foregroundMode) ( me.errorLog = NULL; ) else { if (me.errorLog == NULL) { char "tmp; me.errorLog = ns_malloc(_POSIX_PATH_MAX) ; if (geteuidO == 0) { tmp = "/usr/adm"; } else { tmp = "/tmp" , ) sprintf(me.errorLog, "%s/nsd_port%d.log" , tmp, me.port) } Ns_LogOpen(me.errorLog) ,- ) if Ime.accessLog '= NULL) { Ns_AccessLogOpen(me.acceεsLog) ; } /* * Do the chroot now so everything else is relative to NS_H0ME */ if Ime.chrootMode) { Ns_Log(Notice, "Chroot'mg to the %s directory", me.home), chroo (me.home) ; me.home = "" ; chdir("/"),- } /* * Identify our Web location. */ if (me.self == NULL) { me.self = ns_malloc(strlen(me.hos ) + 20); if (me.port == 80) { sprintf(me.self, "http://%s", me.host) } else { nad.c Tua Mar 21 20:32:37 1995 8 sprintf(me.self, "http://%s • %d" , me.host, me.port), /* * Change UID before the pageroot and cgidirectory access checks */ if (me.uid '= 0) ( Ns_Log(Notice, "Changing uid to %d" , me.uid) ; setuid(me.uid) ; ) else if (geteuidO == 0 it 'me.chrootMode) { Ns_Log(Warning, "Running as root without a chroot; this is insecure ") ) /* * Verify the pageroot exists */ if (me.pageroot == NULL) { char "homepath; homepath = Nε_HomePath( "pageε",NULL,0) , if (homepath == NULL) { fprintf(stderr, "Can't build Ns_HomePathNn" ) ,- exit(1) ,- } me.pageroot = strdup(homepath) , } if ( 'Ns_DιrReadable(me.pageroot) ) { fprintf(stderr, "Can't access NS_PAGEROOT directory %sNn" , me.pageroot) ; exιt(l) , ) * Verify the CGI directory */ if ( (me.cgiPrefix '= NULL) tt (me.cgiDirectory == NULL)) ( char "homepath, homepath = Ns_HomePath(me.cgιPrefix, NULL, 0) , if (homepath == NULL) { fprintf (stderr, "Can't build Ns_HomePathNn" ) ; } me.cgiDirectory = strdup(homepath) ; if ( !Ns_D rReadable(me cgiDirectory)) { fprintf(stderr, "Can't access CGI script directory %sNn' , me.cgiDirectory) ; exιt(l) , ) } /* * Fire up the database. */ if (DM_OpenDB(me.dbserver, me.dbnaune, me.dbuser, me.dbpassword, nsdAlerts) '= DM_OK> { fprintf(stderr, "Can't open database %s on server %s as user %sNn", me.dbnaune, me dbserver, me.dbuser); nad.c Tua Mar 21 20:32:37 1995 /* * Put the database in verbose mode if needed */ if (me.verboseMode) { dm_Verbose = 1 , } else { dm_Verbose = 0, ) /* * Fork into daemon mode if needed */ if ('me foregroundMode) ( int pid, pid = fork ( ) , if (pid < 0) ( fprintf(stderr, "Could not fork'") exιt(l) , ) else if (pid ■ = 0) { Ns_EndMaιnLoop(NULL) , } setsidt ) , ♦if defined) sun ) it 'defined! svr4 ) setpgrp(0, getpidO), ♦else setpgrp( ) , ♦endif umask(O) ; /* " Dup stderr and stdout to the log file */ Ns_LogDup2 (1) , Ns_LogDup2 (2) , Ns_Log(Notice, "Daemon mode, pid = %d' , getpidO) /* * Register the operations */ op = nsOps; while (op->name '= NULL) { Ns__RegιsterOp (op) , ++op, ) /* * Initialize stuff flushable by a SIGHUP */ Ns_Startup( ) , ♦if 0 nad.c Tua Mar 21 20:32:37 1995 10 signal (SIGHUP, SetRestart) ,- ♦endif signal (SIGHUP, SetShutdown) ,- signal (SIGINT, SetShutdown) ,- signal (SIGTERM, SetShutdown) , signal (SIGPIPE, SIG_IGN) ; Ns_Log(Notice, "Accepting: %s " , me . self ) return Ns_MaιnLoop 0 ; static void TableAlert (void) { DM_InιtTableInfo ( ) , Ns_InιtForms ( ) ; ImtMetaTables ( ) ; InitSearchFormPicker ( ] static void ConfigAler (void) { Ns_InιtConfigs ( ) Ns_InιtForms ( ) ,- static void usage(int argc, char "argv) %s [ options ... ] NnNn" is one or more of:Nn" accounting modeNn" archive versioning modeNn" verbose modeNn" run n the foregroundNn" chroot to the page root at startupNn" access log (default: /usr/adm/nsd-accesε . log) Nn" error log (default: /usr/adm/nsd-error. log) n" port number (default: 80) Nn" set uid to {uid) at startupNn" set uid to that of {user} at startupNn" NS_HOME directory (default: /usr/local/ns) Nn" directory GET file name (default: mdex.html) Nn" map directory for -usersNn" pages directory (default: NS_HOME/pages) Nn" CGI prefix (default: None, disabling CGI'slNn" directory of CGI scripts (default: NS_HOME/cgιNn" database server (default: ns)Nn" database name (default: ns)\n" database user (default: nsadmin) Nn" database password (default: nonelNn" server hostname (default: IP hostname) Nn" server location (default: http: //hostname:port) Nn" max open files (default: current process limit) Nn" poll timeout (default: 60 seconds) Nn", argv[0]) ,- static void ShutdownChores (void) nad.c Tua Mar 21 20:32:37 1995 11 signal (SIGCHLD, SIG_IGN) Ns_Log(Notice, "Shutting index daemon down") SendChore( "ns_shutdown' ) , waιtpιd(me.choresPid, NULL, 0), static void SetShutdown(void) { Ns_Log(Notice, "Caught shutdown signal ") if ( 'me resultsPendmg) { Ns_Shutdown() , ) else { me shutdownPendmg = 1, signal (SIGTERM, SIG_IGN) , signal(SIGINT, SIG_IGN) , signal (SIGHUP, SIG_IGN) ) ) void Ns_Shutdown(void) { (void) DM_CloseDB() , ShutdownChores() , Ns_Log(Notice, "<SHUTDOWN>") /* fall through */ static void SetRestar (void) { Nε_Log(Notice, "Caught restart signal") if ( 'me resultsPendmg) ( Ns_Startup() , } else { me.restartPending = 1, signal(SIGHUP, SIG_IGN) , } } void Ns_Startup(void) { static int initialized = 0, char *data_subdιr if ('initialized) { initialized = 1, } else { ShutdownChores() , DM_ReOpenDB(nsdAlerts) , FreeNLPService( ) , FreeNgAnchorProbs() ) nad.c Tua Mar 21 20:32:37 1995 12 Ns_InιtTcl () ; OpenChores() ,- lnitcharnames( ) ; data_subdιr = Ns_LibPath(NS_DATA_SUBDIR,NULL,0) ; if (data_subdιr == NULL) { Ns_Fatal CCan't build Ns_LιbPath") ,- } InitNLPService(data_subdιr) ; InitNgAnchorProbs(data_subdιr) ,- Ns_InιtConfigs() ; DM_InιtTableInfo() ,- Ns_InιtForms() ; ImtMetaTables() ; InitSearchFormPicker() ; Nε_InitPermιssιons() ; static int Ns_DιrReadable(char *dιr) { struct stat st; if (stat(dir, ist) '= 0) { return 0; } if ( !S_ISDIR(st.εt_mode) ) { return 0 ; } if (access (dir, R_OK | X_OK) '= 0) { return 0; } return 1 ; static void About (Nε_Conn *conn) { static NS_DSTRING ds ; static int initialized = 0; if (initialized == 0) { char version[20] ; char port [10] ,- sprintf (version, "%d. %d" ,me.ma 3 orVersιon,me .minorVersion) ,- sprintf (port, "%d" , me. port ) ; ns_dstrmg_ιnit (ids) ; ns_dstπng_varappend (ids, "<HTMLxHEADxTITLE>About this Naviserver" "</TITLEx/HEADxBODYχHl>About this Naviserver" "</Hl>" "<STRONG>Name:</STRONG> ", me. name, "<BR>Nn", "•_STRONG>Versιon: </STRONG> " .version, "<BR>Nn" , "<STRONG>Host:</STRONG> ", me. host, "<BR>Nn", "<:STRONG>Port:</STRONG> ".port, "<BR>Nn" , "<STRONG>Database Server : </STRONG> ", me .dbserver , "<BR>Nn" , " <STRONG>Database Name : < / STRONG> " , me . dbnaune , " <BR> Nn " , "<STRONG>Archιvιng':</STRONG> " ,me . archiveMode ' "Yes" : "No" , "<BR>Nn" , "<ΞTRONG>Chargιng 7 :</STRONG> ", me . chargeMode ~ "Yes" . "No" , " <BR>Nn" , nad.c Tua Mar 21 20:32:37 1995 13 "</BODYx/HTML>Nn" , NULL) ; initialized = 1; } Ns_ReturnHt.nl (conn, 200, ds.string, ds.length) } op.c Tua Fab 28 15:08:47 1995 1 ♦include "nsd.h" ♦include <sιgnal.h> static char rcsιd[] = "Sid op.cv 1 7 1995/02/28 23 08 04 3 ιmbo Exp S' , static mt initialized = 0, static Ns_HashTable prefixes, static Ns_HashTable *MkTable(Ns_HashTable 'tables, char 'table), static Ns_HashTable *FmdTable(Ns_HashTable 'tables, char 'table) static void ReturnUnknown(Ns_Conn 'conn), static Ns_Op DefaultOp = {NULL, NULL, NULL, Nε_FastPathOp, 0), static Ns_Op UnknownOp = {NULL, NULL, NULL, ReturnUnknown, 0) static Ns_Op CgiOp = (NULL, NULL, NULL, Ns_CgιOp, NS_OP_FORK} static void DoOp(Nε_Op * op, Ns_Conn "conn) Ns_Op Ns_NewOρ(char "prefix, char "method, char "name, Ns_OpProc * proc, int flags) { Ns_Op "op, op = ns_malloc(sizeof (Ns_Op) ) , op->prefιx = ns_strdup(prefix) .- op->method = ns_strdup(method) , op->name = ns_strdup(name) , op->proc = proc, op->flags = flags, return op. void Ns_RegιsterOp(Ns_Op * op) ( Ns_HashEntry "he , Ns_HashTable "table , mt new, if ( 'initialized) { Ns_InιtHashTable(tprefιxes, NΞ_ΞTRING_KEYS) , initialized = 1, } table = MkTable(MkTable(tpreflxeε, op->prefιx) , op->method) , he = Ns_CreateHashEntry(table, op->name, tnew) , Ns_SetHashValue(he, op) ; } static Ns_HashTable * FιndTable(Ns_HashTable "tables, char "table) { Ns_HashTable *ht, Ns_HashEntry 'he, he = Ns_FιndHashEntry(tables, table), if (he '= NULL) { ht = Ns_GetHashValue(he) , } else { ht = NULL, } return ht, op.c Tua Fab 28 15:08:47 1995 static Ns_HashTable * MkTable(Ns_HashTable "tables, char "table) { Ns_HashEntry 'he; Ns_HashTable "ht; int new; he = Ns_CreateHashEntry( ables, table, inew) if (new) { ht = ns_malloc(sizeof(Ns_HashTable) ) ; Ns_InιtHashTable(ht, NS_STRING_KEYS) ; Ns_SetHashValue(he, ht) ; ht = Ns_GetHashValue(he) , return ht, ) Ns_DoOp(Ns_Conn *conn) ( Ns_Op "op; if (me.cgiPreflx '= NULL it STREQIme cgiPrefix, cor.n->request->urlv[0] ) ) ( op = tCgiOp, } else { Ns_HaεhTable "methods; methods = FindTable(tpreflxes, conn->request->urlv[0] ) ; if (methods == NULL) { /* This prefix is unknown - run the default op */ op = iDefaultOp; ) else if (conn->request->urlc < 2) { /* This prefix is known but there's no opname. */ op = tUnknownOp; ) else ( Ns_HashTable "ops; ops = FindTable(methods, conn->requeεt->method) ; if (ops == NULL) { /* This method is not handled by this prefix. */ op = tUnknownOp; ) else { Ns_HashEntry "he; he = Ns_FindHashEntry(ops, conn->request->urlv[l] ) , if (he == NULL) { he = Nε_FιndHashEntry(ops, "*" ) ; ) if (he '= NULL) { op = Ns_GetHashValue(he) ; ) else { op = tUnknownOp; ) op.c Tua Fab 28 15 : 08 : 47 1995 switch (Ns_CheckUrl(conn, NULL)) { case NS_ALLOWED: DoOp(op, conn) ; break; case NS_FORBIDDEN: Ns_ReturnForbidden(conn) ; break; case NS_UNAUTHORIZED: Ns_ReturnUnauthorιzed(conn) ,- break; default: Ns_ReturnError(conn, "Could not check %s permission of "URL %s", conn->request->method, conn->requeεt->url) ; break; ) Ns_AccessLog(conn) ; static void DoOp(Ns_Op * op, Ns_Conn 'conn) ( if ((op->flags t NS_OP_FORK) != NS_OP_FORK) { (*op->proc) (conn) ; ) else { int pid; pid = fork() ; if (pid < 0) { Ns_ReturnError(conn, "Could not fork operation!") } else if (pid == 0) { signal(SIGHUP, SIG_DFL) ; signal (SIGPIPE, SIG_DFL) signal (SIGCHLD, SIG_DFL) signal(SIGTERM, SIG_DFL) signal(SIGINT, SIG_DFL) ; Nε_EndMainLoop(conn) ; if (<op->flags i NS_OP_DB) == NS_OP_DB) { DM_ReOpenDB(NULL) ; ) Ns_SetBlocking(conn->socket) ; (* (op->proc) ) (conn) ; exit(O) ; } static void ReturnUnknown(Ns_Conn *conn) ( Ns_ReturnNotImplemented(conn) ; ) urlchaclc.c Sun Mar 12 15 : 03 :27 1995 1 ♦include "nsd .h" static char rcsιd[] = "Sid- urlcheck.cv 1.8 1995/03/12 23.03 29 doug Exp $",- ♦define FieldValuefrow,n) (row->fields[n] value) ♦define MoveFιeld(row,n, o) (to = row->fields[n] value, row->fields[n] .value = NULL) ♦define Boolean(b) ((b) '= NULL it * (b) == 't' ' 1 0) static int initialized = 0; static Ns_HashTable groups; static Ns_HashTable users; static Ns_HashTable costs, static Ns_HashTable permissions; typedef struct User { char *defgroup, t ngroups, char **groups, char 'passwd, ) User; typedef struct Cost { int amount; struct Cost 'next; } Cos ; static Cost 'firstCost; typedef struct Permission { User 'user; char 'group, struct flags { unsigned int user_ok:l; unsigned int group_ok:l, unsigned int world_ok:l; } flags; struct Permission 'next, } Permission; static Permission *firstPermission, typedef struct UrlCache { Ns_HashTable table; char 'method; struct UrlCache 'next; ) UrlCache; static UrlCache 'firstCache; typedef int (FetchProc) (UrlCache * cache, char *url, void "result); extern int HTUU_decode(char *, unsigned char *, int); static void DeieteUser(User 'user); static int FindUser(char 'name, User "user), static int FetchUser(char 'name, User "user), static int UserInGroup(User 'user, char 'group), static ohar *FιndGroup(char 'group); static int FindHierarchal(char 'method, char *url, void "result, FetchProc * proc, N s__HashTable 'caches); static mt FmdCost(char 'method, char *url. Cost "cost) ,- static int FetchCos (UrlCache * cache, char *url, void "cost) , ur1check.c Sun Mar 12 15:03:27 1995 static int FindPermissiontchar *method, char *url, Permission "perm) static int FetchPermission(UrlCache * cache, char *url, void "perm) , static UrlCache *FιndCache(Ns_HashTable "caches, char "method) ; static UrlCache *FetchCache(Ns_HashTable "caches, char "method) ; void Ns_InιtPermιsειons (void) { if (initialized) { Cost "cost, Permission "permission; UrlCache *cache,- Ns_HashSearch hs; Ns_HashEntry "he. /* Flush the known users. */ he = Ns_FιrstHashEntry(tusers , ths) while (he '= NULL) [ DeleteUser(Ns_GetHashValue(he) ) he = Ns_NextHashEntry(ihs) , ) /* Flush the list of URL costs */ cost = firstCost, while (cost '= NULL) ( Cost *c; c = cost, cost = c->next, ns_free(c) ,- } /* Flush the list of URL permissions */ permission = firstPermission, while (permission '= NULL) ( Permission *p, p = permission, permission = p->next, ns_free(p) ,- ) /* Flush the list of URL caches. */ cache = firstCache; while (cache '= NULL) " { UrlCache *c, c = cache; cache = c->next; ns_free (c->method) , Ns_DeleteHashTable(t(c->table) ) ; ns_free (c) ; /* Flush the hash tables */ Ns_DeleteHashTable (tgroups) , Ns_DeleteHashTable(tusers) , Ns_DeleteHashTable(tcosts) , Ns_DeleteHashTable(tpermιssιons) urlcheck.c Sun Mar 12 15 : 03 : 27 1995 } /* Initialize the hash tables */ Ns_InιtHashTable(icosts, NS_STRING_KEYS) , Ns_InιtHashTable(tpermιssιons, NS_STRING_KEYS) Ns_InιtHashTable(tgroups, NS_STRING_KEYS) , Ns_InιtHashTable(tusers, NS_STRING_KEYS) , firstPermission = NULL, firstCache = NULL, firstCost = NULL, initialized = 1, int Ns_CheckUrl (Nε_Conn "conn char "alternateUrl ) { Permiεsion "perm, User "user, char "usernaune , char "passwd, char "url, asser (conn '= NULL), if (alternateUrl '= NULL) ( url = alternateUrl, ) else { url = conn->request->url ) /* Find the permission */ if (FιndPermιssιon(conn->request->method, url, tperm) '= NS_OK) { return NS_ERR0R, /* Check for a completely unaccessible url */ if (perm == NULL | | ( 'perm->flags world_ok tt 'perm->flags user_ok it 'perm->flags group_ok) ) ( return NS_FORBIDDEN, ) /* Check world access */ if (perm-> lags.world_ok) { return NS_ALLOWED, } /* Decode the Auth */ if (conn->authData == NULL) { return NS_UNAUTHORIZED, } Ns_DecodeAuth(conn->authData tusernaune, tpasswd) /* Find the matching user if ("username == 'NO') { return NS_UNAUTHORIZED, } urlcbeck.c Sun Mar 12 15:03:27 1995 if (FindUser(username, tuser) '= NS_OK) { return NS_ERROR; ) if (user == NULL) ( return NS_UNAUTHORIZED; } /* Check the user password. */ if ( (user->passwd '= NULL) it ((passwd '= NULL) it ' (STREQ(user->passwd, passwd)))) ( return NS_UNAUTHORIZED; ) /* Save the authUser in the connection. */ conn->authUser = ns_εtrdup(uεername) ; /* Check the user perm. */ if ( (perm->flags.user_ok it (perm->user == user)) | | (STREQ(username, NS_ADMIN_USERNAME) ) || (perm->flags.group_ok tt UserlnGroupfuser, perm->group) ) ) ( Cost "cost; /* Find out how much this cost. */ if (FmdCost(conn->request->method, url, tcost) '= NS_OK) ( return NS_ERR0R; } if (cost '= NULL ii cost->amount '= 0) ( DeferCharge(username, cost->amount) , } return NS_ALLOWED; ) return NS_UNAUTHORIZED; static void DeleteUser(User "user) { if (user '= NULL) { ns_free(user->passwd) , ns_free(user->groups) ns_free(user) ,- ) static int UserlnGrouptUser "user, char "group) { assert(user '= NULL); if (STREQ(user->defgroup, group)) { return 1; } for (ι = 0; i < user->ngroups; ++ι) { if (STREQ(group, user->groupε[l] ) ) ( return 1; } } urlchack.c Sun Mar 12 15 : 03 :27 1995 5 return 0 ; } static int FindPermission l char "method, char "url , Permission "permission ) { return FindHierarchal(method, url, (void **) permission, FetchPermission, tpermissions ); } static int FmdCost(char 'method, char *url, Cost "cost) ( int status; if (me.chargeMode) { status = FindHierarchal(method, url, (void **) cost, FetchCost, tcosts) ; } else { "cost = NULL; status = NS_0K; } return status; ) static int FindHierarchal (char "method, char "url, void "result, FetchProc * proc, Ns_HashTable "cac hes) { UrlCache "cache; Ns_HashEntry 'he ; mt new ,- assert(url '= NULL); assert(result '= NULL); cache = FindCache(caches, method); /* * Check for an existing entry. */ he = Ns_FιndHashEntry(t(cache->table) , url); if (he != NULL) { 'result = Ns_GetHashValue(he) ; return NS_0K; } /* * Check the database. */ if (Cproc) (cache, url, result) '= NS_0K) ( return NS_ERROR; } if ("result == NULL) { /* * Go up the tree one level and recurse. */ char *p; urlchack.c Sun Mar 12 15:03:27 1995 if Curl == 'NO' | | Curl == '/' ii url[l] == 'NO')) { /* End of the line. */ 'result = NULL; return NS_OK; ) p = strrchr(url, '/'); if (p .'= NULL) { char save; if (p == url) { ++p; } save = *p; •p = 'NO'; if (FindHierarchal (method, url, result, proc, caches) != NS_OK) ( return NS_ERR0R; ) *p = save; /* * Hash this permission for next time. */ he = Ns_CreateHashEntry(t(cache->table) , url, tnew), Ns_SetHashValue(he, "result); return NS_OK; } static int FetchCos (UrlCache * cache, char *url, void "cost) { Form "row; int nrowε; NS_DSTRING sql; char "method; assert(url != NULL); assert(cost != NULL); method = cache->method; ns_dstring_init(tsql) ; ns_dstring_varappend(tsql, "select unique cost_aunount " "from ns_costs " "where cost_url = '", url, "' and cost_method = '", method, "';", NULL); row = DM_ZeroOrOneRow(sql.string, tnrows) ; ns_dstring_free(tsql) ; if (row == NULL) { Ns_Log(Error, "Could not fetch cost of %s %s", method, url); dm_error("Could not check database for URL permission."),- return NS_ERR0R; ) if (nrows == 0) { "cost = NULL; } urlcheck.c Sun Mar 12 15 : 03 : 27 1995 else { Cos t * c ,- c = ns_malloc(sizeof (Cost) ) ; c->amount = atoi(row->fields [0] .value) c->next = firstCost; firstCost = c; "coεt = c; ) DelFor (row) ; return NS OK; static int FetchPermission(UrlCache * cache, char "url, void "permission) assert(url '= NULL) ; assert(permission != NULL); method = cache->method; ns_dstπng_ιnιt(tsql) ; ns_dstrιng_varappend(tsql, "select unique " "permιssιon_user, " "permιssιon_group, " "permissιon_user_ok, " "permissιon_group_ok, " "permiss on_world_ok " "from ns_permιssιons " "where permιssιon_url = '", url, "' "and permιssιon_method = '", method, ", NULL); row = DM_ZeroOrOneRow(sql .string, tπrows), ns_dstrιng_free(tsql) ; if (row == NULL) { dm_error("Could not check database for URL permission."), return NS_ERROR; } if (nrows == 0) ( p = NULL; else { User if (FindUser(FieldValue(row, iuser) '= NS_OK) ( return NS_ERR0R; ) p = ns_malloc(sizeo (Permission) ) ; p->user = user; p->group = FindGroup(FieldValue(row, 1) ) ,- p->flags.user_ok = Boolean(FieldValue(row, 2)); p->flags.group_ok = Boolean(FieldValue(row, 3)); p->flags.world_ok = Boolean(FieldValue(row, 4)); p->next = firstPermission; urlcheck. c Sun Mar 12 15 : 03 : 27 1995 f irstPermission = p ; ) DelForm ( row) ; • permission = p ; return NS_OK; } static int FindUser(char 'name, User "user) { Ns_HashEntry "he; asser (name != NULL); assert (user != NULL) ; he = Ns_FindHashEntry(tusers, naune); if (he != NULL) { "user = Ns_GetHashValue (he) ; } else ( int new; if (FetchUser (name, user) != NS_OK) { return NS_ERROR; ) he = Ns_CreateHashEntry ( tusers , naune , tnew ) , Ns_SetHashValue(he, 'user) ; } return NS_OK; static int FetchUser (char 'name. User "user) { Form *row; char sql [0x100] ,- int nrows,- sprintf (sql, "select user_passwd,user_defgroup "from ns_users where user_naune = '%s'," row = DM_ZeroOrOneRow(sql, tnrows) ; if (row == NULL) { return NS_ERROR; ) u = ns_malloc (sizeof (User) 1 ,- MoveFieldfrow, 0, u->passwd) ; u->defgroup = FindGrouplFieldValue(row, 1)); DelForm(row) ,- urlchack. c Sun Mar 12 15 : 03 : 27 1995 9 u->ngroups = 0; u->groups = NULL; sprintf(sql, "select group_name from ns_groups2users " "where user_name = '%s' , " , naune) ; row = DM_Selec (sql; ; if (row == NULL) { DeleteUser(u) ,- return NS_ERROR; } ns_dstrιng_ιnιt(tgroups1 ; while (DM_GetRow(row) == DM_OK) { char "group; group - F dGroupIFieldValue(row, 0) ) ; ns_dstrιng_nappend(tgroups, (char *) tgroup, sizeo (char *)) ++u->ngroups, ) u->groups = (char **) ns_dstrmg_movestrιng(tgroups) , ns_dstrmg_free(tgroups) , "user = u, ) return NS OK, /* * FmdGroup - store the names of all known groups in a single hash table. */ static char * FmdGroup(char "group) { Ns_HashEntry "he; char 'key; int new; assert (group '= NULL); he = Ns_CreateHashEntry(tgroups, group, tnew), key = Ns_GetHashKey(tgroups, he), if (new) { Nε_SetHashValue(he, key), ) return key; static UrlCache * FindCache(Ns_HashTable 'caches, char 'method) { Ns_HashEntry "he; UrlCache "cache; he = Ns_FιndHashEntry(caches, method), if (he '= NULL) { cache = Ns_GetHashValue(he) ; ) else ( int new; cache = FetchCache(caches, method), he = Ns_CreateHaεhEntry(caches, method, tnew), Nε_SetHashValue(he, cache); } urlcfcack. c Sun Mar 12 15 : 03 :27 1995 10 return cache ; ) static UrlCache * FetchCache (Ns_HashTable "caches , char "method) { UrlCache "cache ; Form "row; char sql [ 0x100 ] ; int nrows ; sprintf(sql, "select method_alias from ns_methods " "where method_name = '%s';", method); row = DM_ZeroOrOneRow(sql, tnrows); if (row == NULL) { return NULL; ) if (nrows != 0) { /* Alias - recurse. */ cache = FindCache(caches, FieldValue(row, 0)); ) else { /" No alias - create a new table. */ cache = ns_malloc(sizeof(UrlCache) ) ; Ns_InitHashTable(t(cache->table) , NS_STRING_KEYS) cache->method = ns_strdup(method) ; cache->next = firstCache; firstCache = cache; } DelForm(row) ; return cache; void Ns_DecodeAuth(char "auth, char "user, char **pasε) { if (auth == NULL) ( "user = "pass = "" ; ) else { static char buf[0x100]; int ndecoded,- char *p; ndecoded = HTUU_decode(auth, buf, sizeof(buf)) ; buf[ndecoded] = 'NO'; p = strchr(buf, ' : ' ) ; if (p != NULL) { *p++ = 'NO' ; } else { p = "" ; "user = bu ; "pass = p; } urlopan.c Tua Mar 21 20:21:56 1995 1 ♦include "nsd.h" ♦define NS_PATHMAX 255 ♦define closesocket close ♦define SOCKET_ERROR -1 ♦include <sys/ ypes.h> ♦include <sys/socket.h> ♦include <netιnet/ιn.h> ♦include <netdb.h> ♦include <arpa/ιne .h> static FILE "OpenLocal (char *url), static FILE "OpenRemote(char *url), static FILE * URLOpenForRead(char *url) { FILE "fp; asεer lurl '= NULL), if ("url •= '/') { fp = OpenRemote(url) , } else if (strncmp(url, "/NS/", 4) == 0) { NS_DSTRING ds, ns_dstnng_mιt (ids ) , ns_dεtrιng_varappend(ids, me self, url, NULL), fp = OpenRemote(ds.string) , ns_dstπng_free(tds) , ) else { fp = OpenLocal (url) , } return fp, } static FILE * OpenLocal (char "urll { char buf[NS_PATHMAX] , char "path; path = Ns_PagePath(url, buf, sizeof(buf), NULL, 0, 0, NULL) if (path == NULL) { return NULL; ) return fopenlpath, "r"), urlopan.c Tua Mar 21 20:21:56 1995 2 char "bp; char buf[1024], assert(url '= NULL); fp = NULL; ns_dstrιng_inιt(ids) ; ns_dstπng_varappend(ids, "GET ", url, " HTTP/1.0", NULL); if (Ns_ParseRequest(ds.εtring, trequest) '= NS_OK) { goto cleanup; ) if (STREQ(request.protocol, "http") tt (request.port == 0)1 ( request.port = 80; ) server.sιn_famιly = AF_INET; ip = ιnet_addr(reques .host) , f dp '= -1) ( memcpy(tserver.sm_addr, tip, sizeof dp)), ) else { struct hostent *hp, hp = gethostbyname(request.hoεt) ; if (hp == NULL) { goto cleanup; } memcpy(tserver.sιn_addr, hp->h_addr, hp->h_length) ,- ) server.sm_port = htons(request.port) ; sock = socket(AF_INET, SOCK_STREAM, 0), if (connect(sock, (struct sockaddr *) t server, sizeof (server) ) < 0) goto closeit; ) ns_dstrmg_trunc(ids, 0), nε_dεtrιng_varappend(tds, "GET ", request.url, " HTTP/1.ONrNnAccept: */*NrNn\r n" , NULL), bp = ds.string; towrite = ds.length; while (towrite > 0) { nwrote = send(sock, bp, towrite, 0) ; if (nwrote == SOCKET_ERROR) { goto closeit; ) towrite -= nwrote; bp += nwrote; } bp = tmpnam(NULL) ; if (bp == NULL) { goto closeit; ) fp = fopen(bp, "w+"); if (fp == NULL) { goto closeit; ) unlmk(bp) ,- while ((towrite = recv(sock, buf, sizeof (buf), 0)) > 0) ( urlopen.c Tua Mar 21 20:21:56 1995 fwπtelbuf, 1, towrite, fp) ,- } if (towrite == SOCKET_ERROR) { fclose(fp) ; fp = NULL; ) else { rewin (fp) ; ) closeit- closesocket(sock) ; cleanup: Ns_RequestFree(trequest) ,- ns_dstrιng_free(ids) ; return fp,- ) /* Contains legal header characters */ int strheader(char "line, t n) { mt 1,- for d = 0; l < n; ι++) { if ( ' lsalnumdme [l ] ) it dined] '= '-')) { return 0 ; } ) return 1, ) /* Saves any headers it reads into the headers form, unless it's NULL The body is returned as a εtring */ char * Nε_Url2Stπng(char "url, Form "headers) { fp = URLOpenForRead(url) , if (fp == NULL) { return NULL; ) line = fgets (buf, sizeof (buf) , fp) ; if (line == NULL) { die: fclose(fp) ; return NULL; > if ( (strlen(lιne) > 4) it (strncmp(line, "HTTP", 4) == 0)) { urlopan. c Tua Mar 21 20 : 21: 56 1995 4 line = fgets I buf , sizeof I buf ) , fp) ; i f ( line == NULL) { goto die ; ) ) /* Eat up headers */ while (((pos = strstrdine, ": ")) != NULL) it (strheader(line, pos - line))) { if (headers != NULL) { "pos = 'NO' ; AppendFormField(headers, line, pos + 2, 0, 0) ; ) line = fgets(buf, sizeof(buf), fp) ; if (line == NULL) { goto die; ) ) /* grab up the body"*/ ns_dstring_init(ids) ; while ((nread = fread(buf, 1, sizeof(buf), fp) ) > 0) { ns_dstring_nappend(tds, buf, nread); } fclose(fp) ; return ns_dstring_movestring(ids) ; aql 8-.t Mar 25 09:49:40 1995 1 SQL statements to build server DBMS structures -r--r gww 1170 Feb 16 07:22 navidrop.sql -r--r doug 14303 Mar 18 21:41 nsbuild.sql -r--r--r-- gww 1137 Feb 15 12:26 nsdrop.sql -rw-rw-r-- gww 2877 Feb 1 10:44 rollforward.a9-al0.sql Files included for reference: nsbuild.sql: builds a server DBMS and all of the structures used to manage content, do archiving, use forms with tables, etc. nabull .agl Sat Mar 18 21:41:15 1995 -- Sid: nsbuild.sql.v 1.32 1995/03/19 05:41:21 doug Exp $ begin transaction; create alerter ns_tables_alert (mechanism = 'callback'), create alerter ns_users_alert (mechanism = 'callback'),- create alerter ns_permιssιons_alert (mechanism = 'callback'),- create alerter ns_confιg_alert (mechanism = 'callback'); create function ns_table_exιsts(text) returns boolean as return (exists (select 1 from tables where table_naune = $1)); create function ns_column_exιsts(tex ,text) returns boolean as return (exists (select 1 from columns,tables where column_naune = S2 and column_member = table_type and table_name = SD) create function ns_table_ιsmeta(text) returns boolean aε return (exists (select 1 from columns,tables where column_name = 'ns_url' and column_type -text = 'text' and column_member = table_type and table_name = $1 and table_name <> 'ns_default_collectιon' ) ) , create table ns_tables ( table_name text not null primary key, table_ιssearchable boolean default 'f, table_maxorderby int default 1, table_ιsmeta boolean default 'f, table_descrιptιon text, chec (ns_table_exιsts(table_name) and table_ιsmeta = ns_table_ιsmeta(table_name) ) ); create index ns_tables_ιndex on ns_tableε using btree(table_name) , create rule ns_tables_ιnsert on insert to ns_tables do alert ns_tables_alert; create rule nε_tables_delete on delete to nε_tables do alert ns_tables_alert; create rule ns_tables_update on update to nε_tableε do alert ns_tables_alert; create table ns_columns ( column_table text not null, column_name text not null, column_descπptιon text, column_htmltag_type text, column_htmltag_data text, unique(coluιtm_table, column_name) , chec (ns_column_exιsts(column_table,column_naune) create index ns_columns_mdex on ns_columns using btree(column_table, column_name) ; create rule ns_columns_ιnsert on insert to ns_columns do alert ns_tables_alert; create rule ns_columns_delete on delete to ns_columns do alert ns_tables_alert; create rule ns_columns_update on update to nε_columnε do alert ns_tables_alert; create table ns_groups ( group_naune text not null primary key, group_descrιptιon text nabuild.aql Sat Mar 18 21:41:15 1995 ) ; create index ns_groups_ιndex on ns_groups using btree(group_name) insert into ns_groups valueε ('public', 'Public Group'); insert into nε_groups values ('users', 'Authorized Users') ,- insert into ns_groups values ('system', 'System Users') ,- create rule ns_groupε_msert on insert to ns_groups do alert nε_users_alert; create rule ns_groups_delete on delete to ns_groups do alert ns_users_alert, create rule ns_groups_update on update to ns_groupε do alert ns_users_alert; create table ns_users ( user_name text not null primary key, user_passwd text, user_defgroup text not null references ns_groups ); create index ns_users_mdex on ns_users using btree(user_naune) , insert into ns_users values ('public', NULL, 'public'); insert into ns_users values ('nsadmin', 'ruffruff', 'system'); create rule ns_users_delete on delete to ns_users do alert ns_users_alert; create rule ns_userε_update on update to ns.users do alert ns_users_alert; create table ns_groups2users ( group_name text not null references ns_groups, user_name text not null references ns.users, unique(group_naune,user_name) ); create index ns_groups2users_user_ιndex on ns_groups2users using btree(user_name) ; create index ns_groups2users_group_ιndex on ns_groups2users using btree(group_name) ; insert into ns_groups2users valueε ('public', 'public'); insert into ns_groups2users values ('public', 'nsadmin'), insert into ns_groups2users valueε ('system', 'nsadmin'); insert into ns_groups2users values ('users', 'nsadmin'); create rule ns_groups2users_ιnsert on insert to nε_groupε2users do alert ns_users_alert; create rule ns_groups2users_delete on delete to ns_groups2users do alert ns_users_alert; create rule ns_groups2users_update on update to ns_groups2users do alert ns_users_alert, create rule ns_users_ιnsert on insert to ns.users do after begin insert into ns_groups2users (group_name, user_name) values (new.user__defgroup, new.user_name) ; alert ns_users_alert; end; create table ns_methods I method_naune text not null primary key, method_alιas text, check(method_alιas = upper(method_alιas) ) ); create index ns_methods_index on ns_methods using btree(method_naune) insert into ns_methods values ('BROWSE', 'GET'); insert into ns_methods values ('HEAD', 'GET'), nabuild.aql Sat Mar 18 21:41:15 1995 insert into ns_methods values ('DELETE' 'PUT' ) , create rule ns_methods_ιnsert on insert to ns_methods do alert ns_permιssιons_alert, create rule ns_methods_delete on delete to ns_methods do alert ns_permιssιons_alert; create rule ns_methods_update on update to ns_methods do alert ns_permιssιons_alert, create table ns_permιssιons ( permιssιon_method text not null, permιssιon_url text not null, permιssιon_user text references ns.users, permιssιon_group text references ns.groups, permιssιon_user_ok boolean not null, permιssιon_group_ok boolean not null, permιssιon_world_ok boolean not null unique(permιssιon_url, permιssιon_method) , check(permιssιon_method = upper(permιssιon_method) ) ) , create index ns_permιssιons_ιndex on ns__permιssιons using btree(permιssιon_url, permιssιon_method) , create rule ns_perπ_ιssιons_ιnsert on insert to ns_permιssιonε do alert ns_permιssιons_alert, create rule ns_permιssιons_delete on delete to ns_permιsειons do alert ns_permιssιons_alert, create rule ns_perπ_ιssιons_update on update to nε_permιssιons do alert ns_permιssιons_alert, insert into ns_permιssιons values ( 'GET','/','public' , 'public','t','t','t'), insert into ns_permιssιons values ( 'PU ','/','nsadmin' , 'users' , ' ' , 't' , 'f' ) , insert into ns_permιssιons valueε ( 'POST', '/','nsadmin' , 'users','t','t','f'), insert into ns_permιssιons values ( 'GET' , '/NS/GetSearchFormPicker' , 'public' 'public' , 't' 't') insert into ns_permιssιons valueε ( 'GET' , /NS/GetEntryForm' , 'public' , ''ppuubblliicc'' ,, ''tt'' ,, ''t'' ,,'t') insert into ns_permιssιons values ( 'GET' , /NS/GetUpdateForm' , 'public' 'public' , 't' , 't' insert into ns_permιssιons values ( • GET' , /NS/GetSearchForm' , 'public' , 'public','t','t','t'), insert into ns_permιssιons values ( 'GET' , /NS/Asset' , 'public' , 'public' ,'t','t','t'l, insert into ns_permιssιons values ( 'GET' , /NS/About' , 'public' , 'public' ,'t','t','t'), insert into ns_permιssιons values ( 'GET' , ' /NS' , 'nsadmin' , 'users' , 't' , 't' , 'f). insert into ns_permιssιons values ( 'POST' , ' /NS' , 'nsadmi ' , 'users' , 't' , 't' , 'f'), -- Make Archive auid ArchiveVersions wide open because -- the related ops do secondary checking on the base urls insert into ns_permιssιons values ( 'GET' , '/NS/ArchiveVersions' , 'public' , 'public' , 't' , '' 't'), insert into ns_permιssιons values ( 'GET' , '/NS/Archive' , 'public' , 'public' ,'t', 't', 't'). nabuild.aql Sat Mar IB 21:41:15 1995 create table ns_costs ( cost_method text not null, cost_url text not null, cost_amount int default 0, unique!cost_method, cost_url), check(cost_method = upper(cost_method) ) ). create index ns_costs_mdex on ns_costs using btree (cost_url, coεt_method) create rule ns_costs_msert on insert to ns_costs do alert ns_permιssιons_alert, create rule ns_costs_delete on delete to ns_costs do alert nε_permιssιons_alert, create rule ns_costs_update on update to ns_costs do alert ns_permιssιons_alert, insert into ns_costs valueε ('GET', '/', 0) , insert into ns_costs values ( 'GET' , ' /NS' , 100), insert into ns_costs valueε ('POST', '/', 0), insert into ns_costs values ('PUT' , '/' , 1000), create table ns_charges ( charge_user text references ns_users, charge_cost mt not null, charge_when timestaunp default current_tιmestamp ); create index ns_charges_index on ns_charges using btree(charge_user) , create function ns_user_charges(text) returns int as select unique sum(charge_cost) from ns_charges where charge_user = $1, create view ns_total_charges as select user_name total_user, ns_user_charges (user_name) total_cost from ns_users. create table ns_confιg ( confιg_name text not null primary key, confιg_value text config valueε 'MaxToReturn' , '20') config values 'HiliteTermε' , 'T') , config values 'MaxOrderB ' , '3'), config values ( 'SchemaVersion' 'Sid: nsbuild.sql.v 1.32 1995/03/19 05 41 2 config values ( 'DefaultCollection' 'ns_default_collectιon' ) , config values ( 'DefaultSmartLinkCollection' , 'nε_default_collectιon' create rule ns_confιg_ιnsert on insert to ns_confιg do alert ns_confιg_alert; create rule nε_confιg_delete on delete to ns_confιg do alert ns_confιg_aler , create rule ns_confιg_update on update to ns_confιg do alert ns_confιg_alert, create table ns_default_collectιon ( ns_url text not null primary key, ns_tιtle text, nε_body doc not null ), create index nε_default_collectιon_by_nε_body on nε_default_collectιon nβbuild.βql Sat Mar 18 21:41:15 1995 5 using dtree(ns_body text_ops) , create index ns_default_collectιon_ιndex on ns_default_collectιon using btree(ns_url) ; insert into nε_tables ( table_naune, table_descrιptιon, table_ιsεearchable, table_ιsmeta) values ( 'ns_default_collectιon' , 'Naviserver Collection of all pages.','t','f ); insert into ns_tables (table_name, table_descπptιon, table_ιssearchable) values ('ns_users', 'Naviserver Authorized Users','t') , insert into ns_tableε (table_name, table_descrιptιon, table_ιssearchable) values ( 'nε_groups' , 'Naviserver User Groups','t') , insert into ns_tables (table_naune, table_descrιptιon, table_ιssearchable) values ( 'ns_groups2users' , 'Naviserver Users to Groups Map'. 't'); insert into ns_tableε (table_name, table_descr ptιon, table_ιssearchable) values ( 'ns_tableε' , 'Naviserver Table of Tables','t') , insert into ns_tables (table_name, table_descrιptιon, table_ιssearchable) values ( 'nsjpenmssions' , 'Naviserver Relative URL Permissions',' ') , insert into ns_tables (table_name, table_descrιptιon, table_ιsεearchable) values ('ns_costs', 'Naviserver Relative URL Charges', 't') , insert into ns_tables (table_name, table_descrιptιon, table_ιssearchable) values ( 'ns_confιg' , 'Naviserver Configuration Parameters','t') , insert into ns_tables (table_name, table_descrιptιon, table_ιssearchable) values ( 'ns_methods' , 'Naviserver HTTP Method Aliases' ,'t' ) ; insert into ns_tables (table_name, table_descrιptιon, table_ιssearchable) values ( 'ns_charges' , 'Naviserver Log of Running Charges','t') , insert into ns_tables (table_name, table_descrιptιon, table_ιεsearchable) values ( 'ns_total_charges' , 'Naviserver View of User Charge Totals','t' ) ; insert into ns_tables (table_name, table_descrιptιon, table_ιssearchable) values ('ns_columns' , 'Naviserver Table Columns Meta Data'.'t'); insert into ns_columns (column_table, column_name, column_htmltag_type, column_htmltag_data) values ( 'ns_permi6sions' , 'peπt_ιssιon_user' , 'SELECTSQL','select user_na_me from ns_users; ' ) , insert into ns_columnε (column_table, column_nautιe, column_htmltag_type, column_htmltag_data) values ( 'ns_permιssιons' , 'permιssιon_group' , 'SELECTSQL' , 'select group_name from ns_groups; ' ) ; insert into ns_columns (column_table, column_na_me, column_htmltag_type, column_htmltag_data) values ( 'ns_permιssions' , 'permιssιon_method' , • SELECT' , *GET PUT POST' ) ; insert into ns_columns (column_table, column_name, column_htmltag_type, column_htmltag_data) values {'ns_columns' , 'column_htmltag_type' , 'SELECTORNULL','SELECTSQL SELECTSQLORNULL SELECT SELECTORNULL RADIO RADIOORNULL TE XTAREA INPUT AUTOINCR' ) ; nabuild.aql Sat Mar 18 21:41:15 1995 6 insert into ns_columnε (column_ able, column_name, column_html ag_type, column_html ag_data) valueε ( 'nε_columnε' , 'column_table' , 'SELECTSQL' , 'select table_name from ns_tables order by table_name, insert into ns_columns (column_table, column_naune, column_htmltag_type, column_htmltag_data) values ( 'ns_groups2users' , 'user_name' , 'SELECTSQL' , 'select user_name from ns_users order by user_naune, ' ) , insert into ns_columns (column_table, column_name, column_htmltag_type, column_htmltag_data) values ( 'ns_groups2userε' , 'group_name' , 'SELECTSQL' , 'select group_naune from ns_groups, ' ) , insert into ns_columns (column_table, column_name, column_htmltag_type, column_htmltag_data) values ( 'ns_costs' , 'cost_method' , 'SELECT' , 'GET PUT POST' ) , insert into nε_columns (column_table, column_name, column_htmltag_type, column_htmltag_data) values ( 'ns_charges' , 'charge_user' , 'SELECTSQL' , 'select user_name from ns.users; ' ) , insert into ns_columns (column_table, column_neune, column_htmltag_type, column_htmltag_data) valueε ( 'ns_total_charges' , 'total_user' , 'SELECTSQL' , 'select user_name from ns_users, ' ) , create table ns_archιves ( archive_path text not null primary key, archιve_type text, archιve_lo large_ob 3 ect ), create index ns_archιves_ιndex on nε_archιves using btree(archιve_path) , -- HTML to ASCII data conversion insert into DocumentConversions (dc_from, dc_to, dc_function) values ( 'html' , 'ascn' , 'html2ascn' ) , create function html2ascιι (text, text) returns text as external name 'MI_HOME/extend/ns/html2ascιι.so(html2aεcιι) language C not variant, -- Privileges for nsadmin on table tables to nsadmin, on table columns to nsadmin, table ns_tables to nsadmin, table ns_columnε to nsadmin, table nε_confιg to nsadmin, table ns.users to nsadmin, table ns.groups to nεadmin, table ns_groups2users to nsadmin, table ns_costs to nsadmin, table ns_permιssιons to nsadmin, table ns methods to nsadmin nabulld.aql Sat Mar IB 21:41:15 1995 grant all on table ns_charges to nsadmin; grant all on table ns_default_collection to nsadmin; grant all on table ns.archives to nsadmin; grant select on table ns_total_charges to nsadmin; grant usage on alerter ns_tables_alert to nsadmin; grant usage on alerter ns_users_alert to nsadmin; grant usage on alerter ns_permissions_alert to nsadmin; grant usage on alerter nε_config_alert to nsadmin; grant usage on function ns_table_exists(text) to nsadmin; grant usage on function ns_column_exists(text,text) to nsadmin; grant usage on function ns_table_ismeta(text) to nsadmin; grant usage on function ns_user_charges( ext) to nsadmin; grant usage on function html2ascii(text, text) to nsadmin; end transaction; praaa Sat Mar 25 10:05:58 1995 Main body of code for the client User interface routines start with NP. -rw-r—r-- 2213 11 NPAbout.c -rw-r—r-- 3724 11 NPAboutW.c -rw-r--r-- 3100 11 NPAuthen.c -rw-r--r-- 3501 11 NPChkLnk.c -rw-r--r-- 3211 11 NPChoose.c -rw-r--r-- 2677 11 NPDest.c -rw-r—r-- 4232 30 NPDoc.c -rw-r--r-- 6127 11 NPDocMn.c -rw-r—r— 2313 11 NPError.c -rw-r--r-- 4081 11 NPFindRp.c -rw-r—r— 3307 41 NPForm.c -rw-r--r-- 2723 11 NPHistor.c -rw-r--r-- 4720 11 NPHotLst.c -rw-r—r-- 4183 11 NPImgFld.c -rw-r--r-- 3744 11 NPInsImg.c -rw-r--r-- 2602 13 NPLatin.c -rw-r--r— 3512 11 NPLink.c -rw-r--r-- 7195 11 NPMap.c -rw-r--r-- 4376 11 NPMime.c -rw-r--r-- 2697 11 NPNewStl.c -rw-r--r-- 2930 11 NPNvLink.c -rw-r—r-- 2561 11 NPOpnOpt.c -rw-r—r-- 7237 30 NPPage.c -rw-r--r-- 12323 55 NPPageMn.c -rw-r--r-- 7958 11 NPPalet.c -rw-r--r-- 5619 11 NPPrfGen.c -rw-r--r-- 4030 11 NPRadio.c -rw-r--r-- 4232 11 NPRefBy.c -rw-r--r-- 4115 11 NPRef o.c -rw-r—r— 3351 11 NPSavOpt.c -rw-r--r-- 4812 11 NPSelLst.c -rw-r--r-- 3282 11 NPSrc.c -rw-r--r-- 1095 11 NPSrcMn.c -rw-r--r-- 4892 11 NPStlCha.c -rw-r--r-- 3229 11 NPStyle.c -rw-r--r-- 2844 11 NPSub it.c -rw-r--r-- 4624 11 NPTaskMn.c -rw-r--r-- 5576 43 NPTextAr.c -rw-r—r— 4628 11 NPTxtFld.c -rw-r—r-- 10186 11 NaviPres.c -rw-r--r-- 48790 11 NaviPreε.h lrwxrwxrwx 14 48 authentc.c -> raw/authentc.c lrwxrwxrwx 11 48 bkgnd.c -> raw/bkgnd.c lrwxrwxrwx 14 48 callback.c -> raw/callback.c lrwxrwxrwx 14 48 callback.h -> raw/callback.h lrwxrwxrwx 13 48 chooser.c -> raw/chooser.c lrwxrwxrwx 13 48 chooser.h -> raw/chooser.h lrwxrwxrwx 13 48 cursors.h -> raw/cursors.h lrwxrwxrwx 13 48 destdlg.c -> raw/destdlg.c lrwxrwxrwx 9 48 doc.h -> raw/doc.h lrwxrwxrwx 14 Mar 22 48 doccache.c -> raw/doccache.c lrwxrwxrwx 13 Mar 22 48 docedit.c -> raw/docedit.c lrwxrwxrwx 14 Mar 22 48 docgraph.c -> raw/docgraph.c lrwxrwxrwx 14 Mar 22 48 docrefer.c -> raw/docrefer.c lrwxrwxrwx 13 Mar 22 48 docview.c -> raw/docview.c lrwxrwxrwx 12 Mar 22 48 fields.c -> raw/fieldε.c lrwxrwxrwx 10 Mar 22 48 find.c -> raw/find.c lrwxrwxrwx 13 Mar 22 fldedit.c -> raw/fldedit.c lrwxrwxrwx 10 Mar 22 func.h -> raw/func.h praaa Sat Mar 25 10:05:58 1995 18:48 help.c -> raw/help.c 18:48 historyd.c -> raw/hiεtoryd.c 18:48 hooksmac.c -> raw/hooksmac.c 18:48 hooksmsw.c -> raw/hooksmsw.c 18:48 hooksx.c -> raw/hooksx.c 18:48 hotlist.c -> raw/hotlist.c 18:48 html.c -> raw/html.c 18:48 html.h -> ra /html.h 18:48 htmlerrs.c -> raw/htmlerrs.c 18:48 imgcache.c -> raw/imgcache.c 18:48 inits.c -> raw/initε.c 18:48 keymore.h -> raw/keymore.h 18:48 linkchck.c -> raw/linkchck.c 18:48 makemap.c -> raw/makemap.c 18:48 navilink.c -> raw/navilmk.c 18:48 pagcache.c -> raw/pagcache.c 18:48 prefs.c -> raw/prefs.c 18:48 source.c -> raw/source.c 16:17 stamp.c 18:48 stamper.c -> raw/stamper.c 18:48 style.h -> raw/style.h 18:48 styledlg.c -> raw/styledlg.c 10 Mar 22 18:48 undo.c -> raw/undo.c 10 Mar 22 18:48 undo.h -> raw/undo.h 9 Mar 22 18:48 url.c -> raw/url.c 10 Mar 22 18:48 util.c -> raw/util.c 10 Mar 22 18:48 view.c -> raw/view.c 10 Mar 22 18:48 view.h -> raw/view.h 13 Mar 22 18:48 viewcmd.c -> raw/viewcmd.c 13 Mar 22 18:48 viewcol.c -> raw/viewcol.c 14 Mar 22 18:48 viewdraw.c -> raw/viewdraw.c 14 Mar 22 18:48 viewedit.c -> raw/viewedit.c 14 Mar 22 18:48 viewfrmt.c -> raw/viewfrmt.c 13 Mar 22 18:48 viewins.c -> raw/viewins.c 14 Mar 22 18:48 viewsave.c -> raw/viewsave.c 13 Mar 22 18:48 viewsel.c -> raw/viewsel.c 14 Mar 22 18:48 viewutil.c -> raw/viewutil.c 13 Mar 22 18:48 win enu.c -> raw/winmenu.c 13 Mar 22 18:48 xvt 3 peg.c -> raw/xvt 3 peg.c 12 Mar 22 18:48 xvtxbm.c -> raw/xvtxbm.c 12 Mar 22 18:48 xxinit.c -> raw/xxinit.c Files included for reference: NPChoose.c: interface for local and remote file chooser NPDoc.c: interface for collections NPDocMn.c: interface for collections menu NPNewStl.c: interface for styles NPNvLink.c: interface for autogeneration of links NPPage.c: interface for page window NPPageMn.c: interface for page menu NPStyle.c: interface for styles chooser.c: local remote file system selection callback.c: client-server communications praaa Sat Mar 25 10:05:58 1995 3 doccache.c: used to implement collections docedit.c: used to implement edit functions collections docgraph.c: used to implement graphing of collections docrefer.c: used to implement collections docview.c: used to implement collections navilink.c: used to implement autogeneration of links styledlg.c: used to implement styles viewcmd.c: used to implement copy and paste address functions chooser.c Tua Mar 21 11:45:47 1995 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved ♦include <xvt h> /* for PtoCstrI) */ static void FullURLSetup(struct chooserinfo "info! { if ( ιnfo->fullurlobserved | | info->chooser_type'=CHOOSER_SAVEPG ) return info->fullurl = ' info->ιnmιnιweb, ) void ChooserSetSel (WINDOW w) { char buf [0x200], "pt, struct chooserinfo "info = (struct chooserinfo *) xvt_vob 3 _get_data(w) if ( ιnfo->chooser_type==CHOOSER_SAVEPG ) { xvt_vob-j_get_tιtle(xvt_wιn_get_ctl(w,FιleChs_URL) ,buf,sizeof (buf) ) pt = strrchr(fsys_nametaιl(buf), ' '), if ( pt==NULL ) pt=buf+strlen(buf1 , xvt_ctl_set_text_sel(xvt_wιn_get_ctl (w,FιleChs_URL) , fsys_nametaιl(buf)-buf,pt-buf) , } else xvt_ctl_set_text_sel(xvt_wιn_get_ctl (w,FιleChε_URL) , 0,SHRT_MAX) , } static void ChooserSetDirList (WINDOW w, char *str) ( char buffer[0x100] , WINDOW list = xvt_wιn_get_ctl(w,FιleChε_DιrLιst) , xvt_lιst_suspend(l st) , xvt_lιst_clear(list) , chooaar.c Tua Mar 21 11 : 45 :47 1995 2 i f t ' strc p lstr " NtDeεktop" ) ) xvt_lιεt_add dιst 0 , "Desktop ) else for I ι=0 , fsys_get_dιr_componant (str , I , buf fer , sizeof (buf fer) ) , ++ι ) xvt_lιst_add ( lιst , 0 , buf fer) , xvt_lιst_set_sel (list , 0 , true ) , xvt_lιst_reεume ( lιst ) , } void XVT_CALLC0NV1 ChooserNewDir (WINDOW w. char *str ) { { char buf[0x100] char buf2[0x100] , char "tail, struct chooserinfo "info = (struct chooserinfo *) xvt_vob-j_get_data(w) Document "doc, ♦if XVT_OS_IS_WINOS if(strlen(str) == 2 tt str[l] == ' ' ) strcat(str "NN ), ♦endif ιnfo->desktop = ('strcmptstr "NtDesktop' ) ) , xvt_vob 3 _get_tιtle(xvt_wιn_get_ctl(w,FιleChs_URL) buf,sizeof(buf) ) , tail = fsyε_nametaιl(buf) , if ( fsys_ιs_url(str) it (strrchr(st ,'/' ) < strstrlstr,' //")+3)) fsyε_buιld_name(str,tail,buf2,sizeof(buf2) ) , doc = DocLookup(str) , if ( ( ιnfo->chooser_type==CHOOSER_SAVEPG | | ιnfo->chooser_type==CHOOSER_SAVEMW) tt fsys_badname(buf2,doc , doc->nametype.fn_local) ) fsys_makegoodnaune(buf2,doc , doc->nametype:fn_local) , xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl(w,FιleChε_URL) ,buf2) , xvt_ctl_set_text_sel(xvt_wιn_get_ctl(w,FιleChs_URL) ,0, 0) , /* Shift back so beginmg is viεible */ xvt_ctl_set_text_sel(xvt_wιn_get_ctl (w,FιleChs_URL) ,SHRT_MAX,SHRT_MAX) /* cursor at en d */ xvt_vob-j_set_tιtle(xvt_wιn_get_ctl (w,FιleChs_TEXT_23) ' (reading )') ChooserSetDirList(w,str) , myfree! (char *) xvt__vob-j_get_data(xvt_wιn_get_ctl (w,FιleChε_DιrLιst) ) ) xvt_vob 3 _εet_data(xvt_wιn_get_ctl(w,FιleChε_DιrLιεt) , (long) copy(str) ) /* change directories if local */ if( 'ιnfo->desktop tt ' fsys_ιε_url(str) ) { DIRECTORY newdir, xvt_fsys_convert__str_to_dιr(str,tnewdir) , xvt_fsys_set_dιr(tnewdir) , ) } { WINDOW files = xvt_wιn_get_ctl (w,FιleChs_Fιle) , WINDOW dirε = xvt_wιn_get__ctl (w,FιleChs_Dιr) struct chooserinfo "info = (struct chooserinfo *) xvt_vob 3 _get_data(w) , info->locked = true, xvt_lιst_suspend(files) xvt_lιst_suspend(dιrs) , xvt_lιst_clear(files) , xvt_lιst_clear(dirs) , xvt_lιst_resume(files) , xvt_lιεt_resume(dirs) , chooser . c Tua Mar 21 11: 45 : 47 1995 3 ιnfo->crud = BrowseURL I str , w) ,- ) navι_set_dlg_waιt_cursor(w) , { WINDOW drives = xvt_wιn_get_ctl (w,FιleChs_Drιves) ; char buf[0x100] , int i , for ( ι=xvt_lιst_count_all (drives)-1, ι>=0, --ι ) { xvt_lιst_get_elt(drives, I,buf,sizeof(buf) ) , if ( pmatch(buf,str) ) ( xvt_lιst_set_sel(drives,l,true) , break, ) ) ) ChooserURLChanged(w) ; } static int ChooεerType(WINDOW w) { εtruct chooserinfo ""info = (struct chooserinfo *) xvt_vob 3 _get_data(w) , int ft, if dnfo->chooser_type == CHOOSER_SAVEPG || ιnfo->chooser_type == CHOOSER_SAVEMW j | ιnfo->chooser_type == CHOOSER_NEWWEB ) ( ft = FT_ALLFILES, } elεe if ( ιnfo->chooser_type==CHOOSER_IMPORT | | mfo->chooser_type==CHOOSER_LINK | | ιnfo->chooser_type==CHOOSER_MAPLINK ) { ft = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,FιleChs_FιleTypes) ) , if ( ft==0 ) ft=FT_HTML; /* Juεt HTML */ elεe if ( ft==l ) ft=FT_IMAGE; else if ( ft==2 ) ft=FT_SOUND, else if ( ft==3 ) ft=FT_VIDEO, else if ( ft==4 ) ft=FT_ALLFILES, /* Anything */ } else if ( ιnfo->chooser_type==CHOOSER_IMAGE ) { ft = xvt_lιst_get_sel_mdex(xvt_wιn_get_ctl (w,FιleChs_FιleTypes) )+5 if ( ft==8 ) ft=FT_ALLFILES, /* GIF, JPEG, xbm */ ) else if ( info->chooser_type==CHOOSER_STYLE ) { ft = FT_STYLE, ) else if ( info->chooser_type==CHOOSER_WEBIZER ) { ft = FT_WEB, ) else { ft = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,FιleChs_FιleTypes) ) , } return ft, ) static struct document 'DocToBrowse!) ( struct document "doc; for (doc=DocHead() ; doc; doc=doc->next) if ( doc->docvιew ) return doc, return NULL, } void ChooserDoBrowse(WINDOW w, struct cstr "rs, struct strandinfo *psι) ( WINDOW files. chooaer.c Tua Mar 21 11:45:47 1995 4 WINDOW dirs; εtruct chooserinfo "info; mt j , k, ft; char buffer[0xl00] ; εtruct document "doc; mt externdir,- char "curdir; if ( ixvtk_vob 3 _ιε_valιd(w) ) /* Has dialogue been dismissed */ return, navι_set_dlg_norm_cursor(w) , ft = ChooserType(w) , info = (struct chooserinfo *) xvt_vob 3 _get_data(w) ,- fileε = xvt_wιn_get_ctl .w,FιleChs_Fιle) , dirs = xvt_wm_get_ctl (w,FιleChs_Dιr) , /* xvt_vob-j_set_enabled(xvt_wιn_get_ctl(w,FιleChs_Ok) ,true) ; */ /* xvt_vob-j_εet_enabled(xvt_wιn_get_ctl(w,FιleChs_Ok) , 'ιnfo->desktop) ; •/ ChooserURLChanged(w) ; xvt_lιst_suspend(files) ; xvt_lιst_suspend(dιrs) ,- xvt_lιst_clear(files) ; xvt_lιst_clear(dirs) ; if(psι->statuε == 200 tt pmatch!"application/x-navibrowse" , psι->type) ) { curdir = (char *) xvt_vob 3 _get_data(xvt_wιn_get_ctl(w,FιleChs_DιrLιst) ) externdir = fsys_ιε_url(curdir) ; mfo->locked = false; xvt_vob 3 _set_tιtle(xvt_wm_get_ctl (w,FιleChs_TEXT_23) , "Directory ") ; 3 = k = 0; ιnfo->ιnmιnιweb = false; while(RsGetLine(rs, buffer, sizeof(buffer) ) >= 0) ( char "type = buffer; char "name = εtrchr(buffer, ' '); *name++ = 'NO' ,- if(strmatch(name,WEBLET_MARK) == 0 | | strcmp(name, " " ) == 0 ) { ♦if 0 if(( 'externdir tt strmatchlname,WEBLET_MARK) == 0) || (externdir ii strcmp(name,WEBLET_MARK) == 0) | | strcmp(name, " ") == 0 ) ( ♦endif /* don't show doc.nvd' */ if { strcmp(name, ".")'=0 ) ιnfo->ιnmιnιweb = true; } else if(strcmp(type, "application/x-navidoc" ) == 0) { if(ιnfo->chσoser_type '= CHOOSER_SAVEMW it info->chooser_type'=CHOOSER_NEWWEB ) xvt_lιst__add(dιrs, 3 ++, naune), if((ft == FT_WEBHTML | | ft==FT_WEB | | f ==FT_ALLFILES) it ιnfo->chooser_type '= CHOOSER_IMPORT) xvt_lιst_add(files, k++, naune); } else if(strcmpttype, "application/x-navidir" ) == 0) ( xvt_lιst_add(dιrs, 3 ++,name) ,- if ( mfo->chooser_type==CHOOSER_WEBIZER ) xvt_lιst_add(files, k++, name), ) else if ( ft==FT_ALLFILES | | ( (ft==FT_WEBHTML || ft==FT_HTML) tt pmatch("text/html", ype) ) ) ( xvt__lιst__add(files,k++,naune) , } else if ((ft == FT_STYLE it pmatch("application/x-navistyle" , ype) ) || (ft == FT_GIF it pmatch! "image/gif",type) ) | | (ft == FT_JPEG it pmatch! "image/ 3 peg" , ype) ) | | (ft == FT..XBM tt pmatch!"image/x-xbitmap" ,type) ) || chooser.c Tua Mar 21 11:45:47 1995 5 (ft==FT_IMAGE ii pmatchI"image/",type) ) | | (ft==FT_SOUND && pmatchI"audio/",type) ) | | (ft==FT_VIDEO it pmatch!"video/",type) ) ) { xvt_lιst_add(flleε,k++,name) ,- } } mfo->fιrεt_browse = false; info->second_browse = false; /* If we failed, but are 3 ust starting up then try and see if we can get a */ /* reasonable doc to save into */ ) else if ( ιnfo->chooser_type'=CHOOSER_OPEN it ιnfo->fιrst_browse tt (doc=DocToBrowse() ) '=NULL ) { ChooserNewDir(w,doc->name) ; info->fιrst_browse = false; info->second_browse = true; ChooserSetSel(w) , /* If that didn't work we better be able to look at the current directory */ } else if ( ιnfo->chooεer_type'=CHOOSER_OPEN tt (ιnfo->second_browse | | ιnfo->fιrst_browse )) ( DIRECTORY "start, start = (DIRECTORY *) xvt_vob 3 _get_data(xvt_wιn_get_ctl(w,FιleChs_Ok) ) , xvt_fsys_convert_dιr_to_str(εtart,buffer,sizeof(buffer) ) , ChooserNewDir(w,buffer) , mfo->fιrst_browse = false, info->second_browse = false; ChooserSetSel(w) , ) else { char buf[30] , xvt_vob-j_set_tιtle(xvt_wιn_get_ctl (w,FιleChs_TEXT_23) , "* Can't Browse:"); xvt_lιst_add(files, 0, ""); xvt_lιst_add(files, 1, ""), xvt_lιst_add(files, 2, xvt_res_get_str(Chooser_Couldnt,buf,sizeof(buf) ) ) , xvt_lιst_add(files, 3, xvt_res_get_str(Chooser_Contact,buf,sizeof(buf) ) ) , xvt_lιs __add(files, 4, xvt_res_get_str(Chooser_Server,buf,sizeof(buf) ) ) , ) xvt_lιst_resume(files) ; xvt_lιst_resume(dιrs) , ιnfo->crud = (Crud *)NULL, } void ChooserBrowseFailed(WINDOW w) ( εtruct strandinfo si, si.status = 401; si.type = "text/plain", ChooserDoBrowse(w,NULL,tsi1 ; ) struct exttype { char *ext; char *type; ); struct exttype *dest_mappιngs (void) ; static int ChooserlnsertServer(WINDOW drives, int I, char 'sname, int 3 , struct exttype *m ap) ( char buf[400] ; int k, char *pt, /* Extract the server off the current file name */ strcpy(buf,sname) ,- pt = strchr(buf,'/') ; if ( pt'=NULL ) { if ( pt[l)=='/' ) { chooser,c Tua Mar 21 11:45:47 1995 pt = strchr(pt+2, '/') ,- if ( pt'=NULL ) pt[l)='N0', else pt = buf; /* It's still valid, 3 ust no final slash */ else pt = NULL, /* Not an url */ ) if I pt==NULL ) buf [0]=' NO', /* Check if it is already in the list */ for ( k=0; buf[0] '='N0' tt k< 3 -l, ++k ) if (pmatchlbuf,map[k] ext)) buf [0]='N0' , if ( buf [0] '='N0' ) xvt_lιst_add(drιveε, ι++ ,buf) , return l, ) static void ChooserFillupServers (WINDOW drives, t I, char "curfile) { struct exttype "map = dest_mappmgs ( ) , t 3 , struct document "doc, for (doc=DocHead( ) , doc, doc=doc->next) /* Add any docs we know about */ if ( doc->docvιew ) /* Show open docs first, closed later */ xvt_lιst_add(drives, ι++,doc->neune) , for (doc=DocHead( ) ; doc, doc=doc->next) if ( 'doc->docview ) xvt_lιst_add(drives, ι++, doc->name) , for ( 3 =0, map'=NULL ii map[3 ] .ext ' =NULL, ++3 ) xvt_lιst_add(drives, ι++,map[3 ] .ext) , if ( fsys_ιs_url (curfile) ) 1 = ChooserlnsertServer(drives, 1 , curflie, ,map) , } void XVT_CALLC0NV1 ChooserFillu (WINDOW w) { static DIRECTORY start, FILE_SPEC fs, struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data(w) , char buf [100] , info->w w; if dnfo->chooser_type == CH0OSER_SAVEPG) xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w, ιleChs_Tιtle) , "Page Location " ) , else if (ιnfo->chooser_type == CHOOSER_SAVEMW) xvt_vob3_set_tιtle (xvt_wιn_get_ctl (w, FιleChs_Tιtle) , "MiniWeb Location ' xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w, FιleChs_Tιtle) ,true) xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w,FιleChs_URL) , rue) , xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w, FιleChs_OpenAsOpt) , ιnfo->chooser_type==CHOOSER_OPEN | | ιnfo->chooser_type==CHOOSER_IMPORT | | ιnfo->chooser_type==CHOOSER_SAVEPG) , if ( ιnfo->chooser_type==CHOOSER_OPEN ) xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w, FιleChs_OpenAsOpt) "File Forma " ) ι = l, if (ιnfo->chooser_type == CHOOSER_SAVEPG | | mfo->chooser_type == CHOOSER_SAVEMW | | ιnfo->chooser_type == CH0OSER_NEWWEB | j ιnfo->chooser_type == CHOOSER_STYLE | | ιnfo->chooser_type == CHOOSER_WEBIZER ) chooser . c Tua Mar 21 11 : 45 :47 1995 7 ι = 0. xvt_vob3_set_vιsιble(xvt_wιn_get_ctl(w,FιleChε_FTText) ,ι) , xvt_vob3_set_vιειble(xvt_wιn_get_ctl (w,FιleChε_FιleTypeε) ,ι) , xvt_vob3_set_vιsιble(xvt_wιn_get_ctl(w,FιleChs_DrιveText) ,1) ,- xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w,FιleChs_Drιves) ,1) , xvt_fsys_get_dιr(istart) , xvt_vob3_set_data(xvt_wιn_get_ctl(w,FιleChs_Ok) , (long)tεtart) , xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w,FιleChε_URL) , fsys_nametaιl (ιnfo->name) ) if ( ιnfo->name[0]=='N0' ) { fs.dir = start; xvt_fsys_convert_dιr_to_εtr(tfs.dir,ιnfo->name,ιnfo->ειze) , } else if ( !fsyε_ιs_url (ιnfo->name) ) { xvt_fsyε_str_to_absfs(ιnfo->name,tfε) ; xvt_fsyε_convert_dιr_to_str(tfs.dir,ιnfo->name,ιnfo->sιze) , ) else if ( strrchr(info->name, '/' ) < strstrdnfo->name, ' //")+3 ) { ) else { char "pt, if ( ( pt = strrchr(info->name, '/')) '=NULL ) "pt = 'NO' , WINDOW types = xvt_wιn_get_ctl (w,FιleChs_FιleTypes) ; WINDOW drives = xvt_wιn_get_ctl(w,FιleChε_Drιveε) , xvt_lιst_suspend(types) ; xvt_lιst_clear(types) ,- if ( ιnfo->chooser_type == CHOOSER_IMAGE ) { xvt_lιst_add(types,0, "gif" ) ,- xvt_lιst_add(types, 1, "3peg" ) ; xvt_lιst_add(types,2, "xbm" ) ,- xvt_lis _add(types,3,xvt_res_get_εtr(Chooser_All,bu ,sizeo (buf)) ) , } else if ( ιnfo->chooser_type == CHOOSER_IMPORT | | ιnfo->chooser_type == CHOOSER_LINK | | ιnfo->chooser_type == CHOOSER_MAPLINK ) { xvt_lιst_add(types,0,xvt_res_get_str(Vιewsave_HTML,buf,εizeof(buf11 ) , xvt_liεt_ad (typeε,1, "Image" ) ; xvt_lιst_add(types,2, "Sound") ,- xvt_lιεt_add(typeε, 3, "Video" ) , xvt_lιst_add( ypeε,4,xvt_res_get_str(Chooser_All,buf,sizeof (buf) ) ) , ) else { xvt_lιst_add(typeε, 0,xvt_res_get_str(Chooser_WebHTML,buf,sizeof (buf) ) ) xvt_lιst_add(types, 1,xvt_res_get_str(Vιewsave_HTML,buf,sizeof(buf) ) ) , xvt_lιst_add( ypes,2,xvt_res_get_str(Chooser_Web,buf,sizeof(buf) ) ) , xvt_lιst_add(types, 3,xvt_res_get_str(Chooser_All,buf,εizeof (buf) ) ) ; } xvt_lιst_set_sel ( types , 0 , rue) , xvt_lιεt_resume ( types ) ; xvt_lιst_suspend (drives ) ; xvt_lιst_clear ( drives ) , ♦i f XVT_OS_ISUNIX xvt_lιst_add ( drives , 0 , " / " ) , / * Perhaps this should read local 7 * / ι = l ; ♦el i f XVT_OS_IS_WINOS { t _getdπve (voιd ) , int _chdrιve ( int ) , char buf [ 0x8 ] ; int curdr = _getdπve ( ) , int 3 ; chooser. c Tua Mar 21 11: 45 :47 1995 8 ι = 0; for(3 = 1; 3 <= 26; - ++ ) { if(_chdπve(3) == 0) { sprintf(buf, " c:NN", 3 - 1 + 'A'); xvt_lιst_add(drives,ι,buf) ,- if(3 == curdr) xvt_lιst_set_sel (drives,1, rue) ; 1++; } } _chdr1ve(curdr1 ; } ♦elif XVT_0S == XVT_OS_MAC xvt_list_add(drives,0, "Desktop" ) , ι = l; ♦endif ChooserFillupServers(drives,1,ιπfo->name) , xvt_lιst_resume(drives) ; } xvt_vob3_set_tιtle(w,xvt_res_get_str( fo->prompt_rιd,buf,sizeof (buf) ) ) , xvt_vob3_set_vιsιble(xvt_wιn_get_ctl(w,FιleChε_DιrLιst) ,true) , ChooserNewDir(w,ιnfo->name) ; ChooserSetSel(w) ,- navι_set_dlg_focus_tf(w,FιleChs_URL) ; ) void XVT_CALLC0NV1 ChooserFileTypes(WINDOW w) { char buffer[400] , char "curdir = (char *)xvt_vob 3 _get_data(xvt_wιn_get_ctl (w,FιleChs_DιrLιst) ) , xvt_vob3_get_tιtle(xvt_wιn_get_ctl(w,FιleChs_URL) ,buffer,sizeof(buffer) ) ; ChooserNewDir(w,curdir) ; xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w,FιleChs_URL) .buffer) ; ChooserURLChanged(w) ; } void XVT_CALLC0NV1 ChooserDymg(WINDOW w) ( struct chooserinfo "info = (struct chooserinfo *) xvt_vob 3 _get_data(w) ,- /* Gets called when the dig box is destroyed */ AbortCrud(info->crud) ,- } void XVT_CALLCONVl ChooserDrives(WINDOW w) { struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data(w) ,- xvt_lιs _get_fιrst_sel(xvt_wιn_get_ctl(w,FιleChs_Dπves) , ιnfo->name, ιnfo->sιze) ; if ( 'strcmp(info->name, "Desktop")) ChooserNewDir(w, "NtDesktop") , else ChooserNewDir(w,ιnfo->name) ; } void _CVT_CALLC0NV1 ChooserFile(WINDOW w) { char buf[0x100] ; char buf2[0x100] ; char "curdir = (char *)xvt_vob3_get_data(xvt_wιn_get_ctl (w,FιleChs_DιrLιst) ) struct chooserinfo "info = (struct chooεerinfo *) xvt_vob 3 _get_data(w) ; if(info->locked) { xvt_scr_beep() ; } else ( xvt_lιst_get_fιrst_sel(xvt_wιn_get_ctl(w, FιleChs_Fιle) , buf, sizeof(buf)) ; chooser.c Tua Mar 21 11:45:47 1995 9 fsys_build_naune(curdir,buf,buf2,sizeof(buf2) ) ; xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w,FιleChs_URL) , buf2) , ChooserURLChanged(w) ,- } } void XVT_CALLC0NV1 ChooserDir(WINDOW w) ( WINDOW dirs = xvt_wιn_get_ctl(w,FιleChs_Dιr) , char buffer[100] ,- int sel = xvt_lιst_get_fιrst_sel(dirε,buffer,εizeof(buffer)) ; struct chooserinfo "info = (struct chooserinfo *) xvt_vob 3 _get_data(w) ; char "curdir = (char *) xvt_vob3_get_data(xvt_wιn_get_ctl (w,FιleChs_DιrLιst) ) , if ( 'sel ) return; if (ιnfo->desktop) { /* Make sure our directory spec is absolute */ if (strchr(buffer, ':') == (char *)NULL) strcat(buffer, ":"), ChooserNewDir(w, buffer); return,- } fsys_add_dιr_componant (curdir,buffer, fo->name,ιnfo->sιze) ; ChooserNewDir(w, info->name) ; } void XVT_CALLC0NV1 ChooserUpDir(WINDOW w) ( /* User opperated the mac-like pulldown list that εhowε directory components"/ /* current dir is at 0 */ WINDOW list = xvt_wm_get_ctl(w,FιleChs_DιrLιst) ; int sel,ι; char buffer[0x200] , subbuf[0x100] ; sel = xvt_lιst_get_sel_ιndex(lιst) ; if ( sel<=0 ) return; /* No op */ ♦if XVT_OS == XVT_OS_MAC if (sel == l) { ChooserNewDir(w, "NtDesktop") , return, } else /"if ( sel'=ι ) */ --1, /* Ignore the desktop in making f le names */ ♦endif xvt_lιst_get_el (list,ι,buffer,sizeof(buffer) ) ; for ( --ι; ι>=sel; --1 ) { xvt_lιs _get_el (list, I,subbuf.sizeof (subbuf) ) ; fsys_add_dιr_componant(buffer.subbuf.buffer,sizeof(buffer) ) ; ) ♦if XVT_OS == XVT_OS_MAC /* Make sure our directory spec is absolute */ if (strchrIbuffer, ':') == (char *)NULL) strca (buffer, " : " ) ; ♦endif ChooserNewDir(w,buffer) ; ) void XVT_CALLC0NV1 ChooserClose(WINDOW w) ( DIRECTORY "orig = (DIRECTORY *) xvt_vob 3 _get_data(xvt_wιn_get_ctl (w,FιleChs_Ok) ) char "curdir = (char *) xvt_vob 3 _get_data(xvt_wιn_get_ctl(w,FιleChs_DιrLιst) ) , myfree(curdir) ; xvt_vob 3 _set_data(xvt_wιn_get_ctl (w,FιleChs_DιrLιst) ,0L) ; xvt_fsys_set_dιr(orig) ; chooser.c Tua Mar 21 11:45:47 1995 10 xvt_vob 3 _destroy(w) , } void XVT_CALLC0NV1 ChooserOk(WINDOW w) ( struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data(w) , char buffer[600] , xvt_vob3_get_tιtle(xvt_wιn_get_ctl(w,FιleChs_URL) .buffer,sizeof (buffer) ) , FullURLSetupdnfo) ; if (( ιnfo->chooser_type==CHOOSER_SAVEPG || info->chooser_type==CHOOSER_SAVEMW) tt fsys_badnaune(buffer, fn_local) ) { navι_dm_post_error(Attrdlg__BadName) , } else if ( fsys__lookslιkedιr(buffer) ) { ChooserNewDir(w,buffer) , ) else if ( (*ιnfo->func) (ιnfo->ctx, buffer, info )) ChooserClose(w) , ) static void ChooserSetButtonName(WINDOW w) { struct chooserinfo "info = (εtruct chooserinfo *) xvt_vob 3 _get_data(w) , char buffer[60] , WINDOW ok = xvt_wιn_get_ctl (w,FιleChs_Ok) , xvt_vob 3 _set_tιtle(ok, xvt_res_get_str(mfo->chooser_type==CHOOSER_OPEN | | info->chooser_type==CH00SER_STYLE'General_0pen info->chooser_type==CHOOSER_IMPORT'General_Import ιnfo->chooser_type==CHOOSER_IMAGE'- , General_lnsert ιnfo->chooser_type==CHOOSER_DELETE''Doccache_Delete ιnfo->chooser_type==CHOOSER_SAVEPG | | info->chooser_type==CHOOSER_SAVEMWGeneral_Save ιnfo->chooser_type==CHOOSER_NEWWEB'General_Create General_Lιnk, buffer,sizeof(buffer) ) ) , } void XVT_CALLC0NV1 ChooserURLChanged(WINDOW w) { struct chooserinfo "info = (struct chooserinfo *) xvt_vob 3 _get_data(w) mt enable=true, char buf er[600] , WINDOW ok = xvt_wιn_get_ctl (w,FιleChs_Ok) xvt_vob 3 _get_tιtle(xvt_wm_get_ctl (w,FιleChε_URL) .buffer,sizeof (buffer) ) , if (( ιnfo->chooser_type==CHOOSER_SAVEPG || o->chooser_type==CHOOSER_SAVEMW) it (fsys_badname(buffer, fn_local) || buf er[0]=='NO' )) enable = false, if ( fsys_lookslιkedιr(buffer) ) { char "curdir = (char *) xvt_vob3_get_data(xvt_wιn_get_ctl(w,FιleChs_DιrLιεt) ) , char ch = buffer[strlen(buffer)-1] , if ( ch=='/' | | ch=='NN' | | ch==' ' ) buffer[strlen(buffer)-1]=' O' , if ( fsys_urlcmp(curdir,buffer)==0 ) { enable = false, if ( mfo->looks_lιke_dιr ) ChooserSetButtonNaune(w) ; ιnfo->lookε_lιke_dιr = false } else if ( ιnfo->lookε_lιke_dιr'=1 ) ( xvt_vob3_set_tιtle(ok, xvt_res_get_str(General_BrowseDιr,buffer,sizeof(buf er) ) ) , ιnfo->looks_lιke_dιr = true, ) } else if ( ιnfo->looks_lιke_dιr ) { ChooserSetButtonNaume(w) mfo->looks_lιke_dιr = false, chooser. c Tua Mar 21 11 : 45 :47 1995 11 ) if ( enable '= info->enabled ) { xvt_vob 3 _set_enabled(ok,enable) , ιnfo->enabled = enable,- } ) void XVT_CALLC0NV1 ChooserOptions(WINDOW w) { struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data(w) , if ( ιnfo->chooser_type==CHOOSER_OPEN ) { if ( 'navι_xvt_dlg_create_res(WD_MODAL, OpenOpt, EM_ALL, OpenOpt_eh, (long) info): xvt_dm_post_error("Can't open dialog"), } else if ( ιnfo->chooser_type==CHOOSER_IMPORT | | ιnfo->chooser_type==CHOOSER_SAVEPG : { if ( 'navι_xvt_dlg_create_res(WD_MODAL, ImportOpt, EM_ALL, ImportOpt_eh, (long) inf o)) xvt_dm_post_error("Can't open dialog"); ) void XVT_CALLC0NV1 Choosel (void "ctx, int prompt_rιd, char "name int size, int chooser_type, int ("func) (void "ctx, char *, struct chooserinfo *)) { struct chooserinfo info; memset(tinfo, 'NO' ,sizeof(info) ) , ιnfo.prompt_rιd = prompt_rιd; info,name = name, info.size = size, info.chooser_type = chooser_type; info.func = func; info.ctx = ctx; info.saveimages = 1, /* save relative */ info.fullurl = (chooser_type '= CHOOSER_IMPORT) , info.fullurlobserved = false, ιnfo._as_type = 0; /* HTML for saveas, OPEN_DEFAULT for openaε */ info.locked = 0; info.fιrst_browse = true, info second_browse = false, info looks_lιke_dιr = 2, /* Set to invalid state, force update */ info.enabled = true, info.desktop = false, info.crud = NULL; info.enabled = 2; if ( 'navι_xvt_dlg_create_res(WD_MODAL, FileChs, EM_ALL, FιleChs_eh, (long)tιnfo)) xvt_dm_post_error("Can' open dialog"); } void OpenOptOK(WINDOW w) { struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data(w) , WINDOW filters = xvt_wιn_get_ctl(w,OpenOpt_Format) , ιnfo->_as_type = xvt_lιεt_get_sel_ιndex(fliters) , if ( ιnfo->_as_type==-l ) ιnfo->_as_type = OPEN_DEFAULT; xvt_vob3_destroy(w) ; ) void OpenOptFillup(WINDOW w) { struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data ( w ) ; WINDOW filters = xvt_wιn_get_ctl (w,OpenOpt_Format) ; mt i; chooser.c Tua Mar 21 11:45:47 1995 12 struct exttype { char type; char "cmd; } *ιnput_mappιngs(void) struct exttype *ιnput; char buf [70]; xvt_lιst_suspend(filters) , xvt_lιst_clear Ifllterε) , xvt_lιs _add{fliters,OPEN_DEFAULT,xvt_res_get_str(Chooser_Default,buf, sizeof (buf) ) ) xvt_lιεt_add(fllterε, OPEN_HTML,xvt_reε_get_str(Vιewsave_HTML,buf, sizeof (bu ) ) ) , xvt_lιst_add(fliters,OPEN_TEXT,xvt_res_get_str (Vιewsave_Text, buf , sizeof (buf) ) ) ,- xvt_lιst_add(fιlters,0PEN_D0CUMENT,xvt_res_get_str(Chooser_Web,buf, sizeof (buf) ) ) , xvt_lιst_add(fιlters,OPEN_SAVE,xvt_res_get_str (Chooser_OpenSave, buf, sizeof (buf) ) ) , input = ιnput_mappιngs ( ) ; for ( ι=0; inpu [l] .type!=NULL; ++ι ) xvt_lιst_add(fliters,OPEN_FILTERS+ι, ιnput[ι] type); xvt_lιst_set_sel (filters, ιnfo->_as_type, true) , xvt_lιst_resume(filters) ; } void ImportOptFormat (WINDOW w) { WINDOW filters = xvt_wιn_get_ctl (w, ImportOpt_Format) , int satype = xvt_lιst_get_sel_mdex (filters) , int on = (satype==0); struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data (w) , char buffer [1000] , "pt, Document "doc, xvt_vob3_set_vιsible(xvt_wm_get_ctl (w, ImportOpt_SavePιct) ,on) , xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w, ImportOpt_None) ,on) ; xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w, ImportOpt_Relatιve) ,σn) ; xvt_vob3__set_vιsible(xvt_wιn_get_ctl (w, ImportOpt_All) ,on) ; xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w, ImportOpt_Full) ,on) ,- if ( ιnfo->w'=NULL_WIN ) { xvt_vob3_get_tιtle(xvt_wιn_get_ctl (ιnfo->w,FιleChs_URL) .buffer, sizeof (buffer) ) ,- pt = strchr{fsys_nametaιl {buffer) , '. ') ; if ( pt==NULL ) pt = buffer+strlen(buffer) , if I ιnfo->chooser_type == CHOOSER_IMPORT ) /* Don't mess with the name, it's on the disk, user knows what s/he's doing */ else if I satype==0 ) { if ( ipmatchl "text/html " ,guess_suffIX(buf er) ) | | strlen(strrchr (buffer, ' '))>4 ) I doc = DocLookupContaιnsFιle(buffer) , if ( ( doc'=NULL it doc->nametype==fn_dos 1 | | XVT_OS_IS_WINOS 1 strcpy(pt, " .htm" ) ,- else strcpy(pt, " .html") ; } } else if ( satype==l | | satype==2 ) strcpy(pt, " .txt" ) ; ♦if XVT_OS_ISUNIX else if ( satype==3 ) strcpy(pt, " .ps" ) , ♦endif xvt_vob3_set_tιtle (xvt_wιn_get_ctl dnfo->w, FιleChs_URL) .buffer) , ) ) void ImportOptOK(WINDOW w) { struct chooserinfo " nfo = (struct chooserinfo *) xvt_vob3_get_data(w) WINDOW filterε = xvt_wιn_get_ctl (w, ImportOpt_Forma ) ; mfo->_as_type = xvt_lιst_get_sel_ιndex( liters) , if ( info->_as_type==-l ) mfo->_as_type = 0; chooser.c Tua Mar 21 11:45:47 1995 13 if ( xvt_ctl_ιs_checked(xvt_wιn_get_ctl(w,ImportOpt_None) ) ) info->saveιmages = 0; else if ( xvt_ctl_ιs_checked(xvt_wm_get_ctl(w,ImportOpt_All )) ) ιnfo->saveιmages = 2, else ιnfo->saveιmages = 1, in o->fullurl = xvt_ctl_ιs_checked(xvt_wιn_get_ctl(w,ImportOpt_Full) ) , xvt_vob 3 _destroy(w) ; } void ImportOptFillup(WINDOW w) { struct chooserinfo "info = (struct chooserinfo *) xvt_vob3_get_data(w) , WINDOW filters = xvt_wιn_get_ctl(w,ImportOpt_Format) ,- int 1,3, char buf1[200] ; struct exttype { char "type, char "cmd, } "savefιlter_mappιngs(void) , struct exttype *sf = savefιlter_mappιngs() , FullURLSetup nfo) , ιnfo->fullurlobserved = true; xvt_lιst_suspend(filters) , xvt_lιst_clear(filters) , ι = 0, xvt_lιst_add(filters,ι++, vt_res_get_str(Vιewsave_HTML,buf1,sizeof(buf1) ) /""HTML"*/) , if ( mfo->w'=NULL_WIN ) { xvt_vob 3 _get_tιtle(xvt_wιn_get_ctl (info->w,FιleChε_URL) ,buf1,εizeof(buf1) ) . if ( ιnfo->chooser_type==CHOOSER_SAVEPG it ' fsys_ιs_url(buf1) ) { xvt_lιst_add( ilters,ι++,xvt_res_get_str(Vιewsave_NoBreaks,buf1,sizeo (buf1) ) / ""Text without linebreaks"*/) ; xvt_lιst_add( ilters,ι++,xvt_res_get_str(Vιewsave_Text,bufl,sizeof(buf1) ) /""Te xt"*/) ; ♦if XVT_OS_ISUNIX xvt_lιst_add(filters, ι++,xvt_res_get_str(Vιewsave_PS,buf1,sizeof(buf1) ) /""Post Script"*/) ; ♦endif for ( 3=0; sf[31 -type'=NULL, ++3 ) xvt_lιst_add(filters,1++,sf[ ] type) , ) } if ( info->_as_type>=ι ) info->_as_type = 0, xvt_lιst_set_sel(filters, -1, false) , xvt_lιst_set_sel(filters, ιnfo->_as_type,true) ; xvt_lιst_resume(filters) , xdCheckRadioButton(w, ImportOpt_None+ιnfo->saveιmages, ImportOpt_None, ImportOpt_All) , xvt_ctl_set_checked(xvt_wιn_get_ctl(w,ImportOpt_Full) ,ιnfo->fullurl) , ImportOptFormat(w) , ) int DoImportOptions nt 'fullurl) { struct chooserinfo info; me set(tinfo, 'NO' ,sizeof(info) ) ; mfo.chooser_type = CHOOSER_IMPORT, mfo.saveimages = 1; /* save relative */ info.fullurl = false, info fullurlobserved = false, if ( 'navι_xvt_dlg_create_res(WD_MODAL, ImportOpt, £_M__ALL, ImportOpt_eh, (long) tinfo)) xvt_dm_post_error("Can't open dialog"), "fullurl = info.fullurl; return! mfo.saveimages ), chooser. c Tua Mar 21 11:45:47 1995 14 callback.c Frl Mar 24 16:16:58 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved */ ♦include <xvt.h> ♦include <stdιo.h> ♦include <memory.h> ♦include "view.h" ♦include "doc.h" ♦include "xlocal.h" ♦include "callback.h" ♦include "str h" ♦include "guess h" ♦include "NaviPres.h" ♦include "weblet.h" ♦include "func.h" ♦include "nsdefs.h" int dbg_prιntf (const char "fmt, ), long millisec() , long parttime = 0, long fulltime = 0, int prefetch_pages = false, XVT_IMAGE Badlmage(voιd) , XVT_IMAGE Unknownlmage(void) , void *make_partιal_context(struct cstr "rs) void del_partιal_context(void *), XVT_IMAGE partιal_read_gιf(void *), XVT_IMAGE _xvt_ιmage_read_gιf(struct cstr *), XVT_IMAGE xvt_ιmage_read_3peg(char *), XVT_IMAGE navι_ιmage_read_xb (char *), int fsys_delete(char *), void ViewScrollToBookmark(WINDOW, char *), void ViewRedrawImages(View 'view, Image "image), void ThιngSetMessage(Vιew "view, char *msg) int CrudForVιew(Vιew *, enum crud_abort, void *), void DocRedrawDP(Document "doc, DocPart "dp), void DocPosition(Document "doc, DocPart "dp), int WritePage(Page "page, int dobase, int ("fund (/* ■ " ■ ' */) void "ctxl , int HTUU_encode(unsigned char *, unsigned t, char *), mt CacheFlushlchar *), Crud *_QueueCrud(Crud "crud, int ("func) (void *,ιnt), void *ctx) int ιnsync(voιd "arg) { return dbg_prιntf( (char *)arg), ) int IsVιew(Vιew "view) { return(view it vιew->tag == TAG_VIEW) , } extern View "ViewFromWindow(WINDOW) , View *_VιewAlterURL(Vιew "view, Page "page, char "anchor, int newview, void *ctx) ( if ('newview it view it vιew->tag == TAG_DOCUMENT) { DocAddPageName( ( (DocView *)view)->doc, page->url, -1 -1) return view, ) if(newview I I 'IsVιew(vιew) ) callback.c Fri Mar 24 16:16:58 1995 2 view = VιewFromWιndow(CreatePageWιntpage) ) , if (vιew->page '= page || anchor) { char buf[0x200] , xvt_res_get_str(Callback_Done,buf,sizeof(buf)) /* "done "*/, if ( vιew->page'=page ) { strcat(buf, page->url), ViewAlterURLIview, page), } if(anchor) ( strcat(buf, "♦") strcatfbuf, anchor), VιewScrollToBookmark(vιew->w, anchor) , } ThingSetMessagelview buf), ) if ( 'CrudForView(view,dont_abort,ctx) ) VιewResetCLUT(vιew) , if ( page->newwarned ) VιewStdMsg(vιew) , return view, } int _SyncCrud(Crud "crud) { xvt_scr_set_busy_cursor() , return SyncCrud(cru ,msync, "_SyncCrud" ) , } static void Prefetch(char "url, char *ref) { char anchor[40], char "buf; int sizebuf, buf = myalloc(sizebuf = strlenlref)+strlen(url)+30) , URLTrans(ref, url, NULL, buf, anchor, sizebuf, εizeo (anchor)) , if(pmatch(guess_suffιx(buf) , "text/html") ) PrefetchCrud(buf) , my ree(buf) , ) static void PrefetchTroll(Para "para, char *url) { static char ref[0x200], while(para) { char "pt = para->text, ιf(pt) { while("pt) ( while("pt it "pt '= HTML_MARK) pt++, ιf(*pt == HTML_MARK) { int tag = HTML_tag(pt) , if(tag == A_TAG) { HTML_HasAttr(pt, ref, sizeof (ref), "HREF' ), Prefetch(url, ref), pt += Taglncr(pt), whιle(*pt) ( while("pt ii "pt '= HTML_MARK) pt++ ιf(*pt == HTML_MARK) { tag = HTML_tag(pt) , if(tag == END TAG it ((unsigned char *)pt1 [HTML_END_TAG] == A_TAG) callback.c Fri Mar 24 16:16:58 1995 3 break, } pt += Taglncr(pt) , } } ) pt += Taglncr(pt), } ) ) PrefetchTroll(para->first, url), para=para->post, } } void TransferHPageToPage(HtmlPage "hpage.Page "page,struct strandinfo "psi, int mod) ( DocPart "dp, PageFreeContents(page) , PageFromHtml(page, hpage, 0), if ( prefetch_pages ) { PrefetchCrud( (dhar *)0) , PrefetchTroll (page->first, page->url) , } page->modιfyable = mod, page->orthodata = (psι->status '= 200), if ( page->orthodata ) page->modιfyable = false, page->docname = psι->docu_nenf> copy(psι->document) NULL, if ( page->docname ) { if ( page->doc == NULL ) page->doc = DocLookup(page->docname) , /* Problem the docnaune may not be the name we have stored m the cache */ /* page->url==http.//navisoft.com/ , page->docname==http //gore navisoft */ if ( page->doc == NULL ) page->doc = DocLookupContaιnsFιle(page->url) , /* Someone had commented out the Lookup This meant that we always */ /* inserted the page into the doc even if it were already there, and */ /* so the document was marked dirty, and was saved back */ dp = NULL; if ( page->doc tt 'page->orthodata tt (dp=LookupDocPart(page->doc, fsys_nametaιl (page->url) ) )==NULL ) { DocAddPage(page->doc,page,NULL,2,-1) , DocGraphNew(page->doc) ; DocDrawNew(page->doc) ; DocRedraw(page->doc) ; } else if ( page->doc tt dp'=NULL ) { dp->loaded = page, if ( 'page->orthodata tt 'dp->exιsts ) { /* Shouldn't get here */ dp->exιsts = true, myfree<dp->tιtle) , dp->tιtle = copy(page->tιtle) , ) strcpy( sys_nametaιl(page->url) , fsys_naunetaιl(dp->relurl) ) , } ) page->readιn = true, page->readstarted = false, if(page->style '= NULL it page->sheet == NULL) page->sheet = FιndStyle(page->style, page->url, page->base) , else if (page->sheet == NULL) page->sheet = defstyle; callback.c Fri Mar 24 16:16:58 1995 if(page->refresh) { extern unsigned long time(unsigned long *), page->reload = tιme(O) + page->refresh, } ViewUpdateAll (page, NULL) } Page *PageFromStrand(struct cstr "rs, struct strandinfo "psi, char "url, char "origurl, in t ot) { HtmlPage hpage; Page "page = PageLookup(url, "", NULL), t reload; if ( page==NULL it origurl '=NULL ) page = PageLookup(origurl, "', NULL), reload = false, if ( page==NULL ) page = newPage(url,"",NULL,NULL) ; else { ViewsSaveSel (page) ; reload = true; ) page->orιgurl = copy(origurl) ; memse (thpage, 'NO', sizeof(HtmlPage) ) ; hpage.url = copy(page->url) ; if (ot==OPEN_HTML | | (ot==OPEN_DEFAULT it pmatch("text/html",psi->type) ) ) ( FillHtmlPage(ihpage, (int (*) (voιd *))RsReadC, rs) , } else { char *f = RsForceFile(rs) , textblob tb, tb.state = 0; tb.fp = fopen(f, "r" ) ; FillHtmlPagelthpage, (int (*)(voιd *) )text2html, itb), fcloseltb.fp) , ) TransferHPageToPage(ihpage,page,psi, sι->modιfyable) , if ( reload ) { ViewsRefresh(page) , i f ( page->doc ' =NULL ) { DocLinkCheck(page,NULL) , DocRedraw(page->doc) , ) ) VιewsNotιceLoad(page) ; return page, } struct crtctx { unsigned int noshow :1, unsigned t newview: 1, View "view, Page "page, char "url, }; static int new_callback(void "vctx, int rid), static Crud *_new(voιd "vctx) { struct crtctx "ctx = (struct crtctx *)vctx, callback.c Fri Mar 24 16:16:58 1995 5 return _QueueCrud(RetrιeveCrud(ctx->url, NULL), new_callback, ctx) ,- ) static int new_callback(voιd "vctx, int rid) { εtruct crtctx "crtctx = (struct crtctx *) vctx; Page "page = crtctx->page; struct strandinfo si; struct cstr "rs = RsOpenId(rιd,tsi) ; switch ( si.status ) { case 301: case 302: myfreelcrtctx->url) ; crtctx->url = copy(si.type) ,- _new(vctx) ; return 0; case 401: DoAuthDlg(crtctx->url, .new, vctx), return 0; default- if ( page->doc == NULL ) ( page->doc = newDoc(page->docname) ; docεlurp(page->doc,rs,tsi) ; if ( page->doc->template!=NULL tt PageLookup(page->doc->template,page->url,NULL)==NULL 1 ( char "buffer; int sizebuf; myfree(crtctx->url) ; buffer = myalloc(sizebuf=strlen(page->doc->name)+εtrlen(page->doc->tempiat e)+30) fsys_buιld_name(page->doc->name,page->doc->template,buffer,sizebuf) crtctx->url = copy(buffer) ; QueueCrud(RetrιeveCrud(crtctx->url,0) ,new_callback,crtctx) ; myfree(buffer) ,- return 0; } } else { PageFromStrand(rs,isι,crtctx->url,NULL,OPEN_DEFAULT) ; ) DocSetPageToTemplate(page->doc,page) ,- PageDefaultTitle(page) ; DocInsertPart(page->doc, fsyε_nametaιl (page->url) .page) , DocGraphNew(page->doc) , DocDrawNew(page->doc) ; DocSetDirty(page->doc) ; page->readιn = true; page->readstarted = false, PageSetChanged(page,page->doc'=NULL) ; if ( !crtctx->noshow ) _VιewAlterURL(crtctx->vιew, page, NULL,crtctx->newvιew,NULL) ; ) RsClose(rs) ; myfree(crtctx->url) ; myfree(crtctx) ; return 1; ) static vo d FillupNewPage(formctx "ctx,struct strandinfo *psι) { char "url = (ctx->form ' ctx->form->URL : ctx->url) , Page "page; struct crtctx "crtctx; if ((page = PageLookup(url,"",NULL) )==NULL tt (ctx->orιgurl==NULL | | (page=PageLookup(ctx->orιgurl, "" ,NULL) )==NULL) ) page = newPage(url, " " ,NULL,NULL) ; else callback.c Fri Mar 24 16:16:58 1995 6 PageFreeContents(page) ; if ( ctx->origurl!=NULL ) { myfree(page->orιgurl) ,- page->orιgurl=copy(ctx->orιgurl) ,- ) page->docname = psi->document?copy(psι->document) :NULL; page->modιfyable = true; page->new = page->newwarned = true; if ( page->docname!=NULL ) page->doc = DocLookup(page->docname) ,- if ( page->doc==NULL ) { page->doc = DocLookupContamsFile(page->url) ; myfree(page->docnaune) ,- page->docname = NULL; if ( page->doc!=NULL ) page->docname = copy(page->doc->name) , ) if ( page->docname==NULL ) goto finished; if ( page->doc'=NULL it (page->doc->template==NULL || (page->doc->template'=NULL tt PageLookup(page->doc->template,page->url,NULL) '=NULL ))) { if ( page->doc->template!=NULL ) DocSetPageToTe plate(page->doc,page) , PageDefaultTιtle(page) DocInsertPart(page->doc,fsys_nametaιl(page->url) ,page) ,- DocGraphNew(page->doc) DocDrawNew(page->doc) ; DocSetDirty(page->doc) goto finished; ) crtctx = (struct crtctx *) myalloc(sizeof(struct crtctx)); crtctx->noshow = ctx->noshow; crtctx->vιew = ctx->vιew; crtctx->newvιew = ctx->newvιew; /* Won't have an anchor */ crtctx->page = page; if ( page->doc==NULL ) crtctx->url = copy(page->docname) ; else { char "buffer; int sizebuf; buffer = myalloc(sizebuf=strlen(page->doc->name)+strlen(page->doc->template)+30) fsys_build_naune(page->doc->name,page->doc-> emplate,buffer,εizebuf) ; crtctx->url = buffer; ) QueueCrud(RetrιeveCrud(crtctx->url,0) ,new_callback,crtctx) ; return; finished: page->readιn = true; page->readstarted = false; PageSetChanged(page,page->doc!=NULL) ; if ( !ctx->noshow ) _VιewAlterURL(ctx->vιew, page, ctx->anchor,ctx->newvιew,ctx) ; ) static Page "Pagelmage(const char "url.conεt char "document) { /* Dummy up an HTML page which refers to the image we 3 ust loaded */ char buffer[1000] ,- εtrcpy(buffer,url) ; ♦if XVT_OS_IS_WINOS callback. c Fri Mar 24 16 :16: 58 1995 7 strcat (buf fer , " .htm" ) , ♦ else strcat(buffer, " .html" ) ,- ♦endif page = PageLookup(buffer, "" ,NULL) ,- if ( page==NULL ) page = newPagelbuffer,"" ,NULL, (char *)url); pt = strrchr(url, '/') ; if ( pt'=NULL ) url = pt+1; ♦if XVT_OS_IS_WINOS pt = strrchr(url, 'NN') ; if ( pt'=NULL ) url = pt+1; ♦elif XVT_OS==XVT_OS_MAC pt = strrchr(url,':') ; if ( pt'=NULL ) url = pt+1; ♦endif page->fιrst = (Para *) myalloc(εizeof(Para) ) , HTML_FιllTag(buffer,IMG_TAG) ; len = strlen(url) ,- strcpy(buffer+HTML_HEAD_LEN, "SRC=") , strcpy(buffer+HTML_HEAD_LEN+4,ur1) ; buffer[HTML_LEN_LOW] = (len+4)%256; buffer[HTML_LEN_HIGH] = (len+41/256, page->fιrst->text = copyn(buffer,len+HTML_HEAD_LEN+4) page->fιrst->tlen = len+HTML_HEAD_LEN+4, page->modιfyable = false; page->readm = true; page->readstarted = false; page->docname = document ' copy! document ) : NULL; if ( page->docname ) page->doc = DocLookup(page->docname) ; page->orthodata = true; page->sheet = defstyle; return! page ) , ) static struct exttype { char 'type; char *cmd; } dιsptab[] = { ♦if XVT_OS_ISUNIX "application/postscript" , "ghostview" , "image/x-xbitmap*, "xv" , static int freeable=0; static struct exttype 'disppt = disptab; struct exttype 'extern_mappιngs(void) { return! disppt ); } void set_extern_mappιngs(struct exttype "newmap) ( int ι; callback.c Fri Mar 24 16:16:58 1995 8 if I freeable ) { for ( ι=0; dispp [l] .type'=NULL, ++ι ) ( myfree(disppt[1] .type) , myfree(disppt[I] .cmd) ; ) myfree(disppt) ; } disppt = newmap; freeable = 1, } static struct exttype ιnputtab[]={ (char *)0, (char *)0 ) ,- static int static struct exttype 'inputpt = inputtab; struct exttype *ιnput_mappιngs(void) ( return( inputpt ) ; ) void set_ιnput_mappιngε (struct exttype "newmap) ( t i; if I lfreeable ) { for ( ι=0; inputpt[i].type'=NUL ; ++ι ) ( myfree(inputpt[l] .type) , myfree(inputpt[l] .cmd) , ) my ree(inputpt) ; } inputpt = newmap; lfreeable = 1; } static mt DisposeSave(const char "file, const char "url, const char "type) { FILE_SPEC fs; register FILE "fpl, *fp2, mt ret; char buf[1000] , frmt[60], register int ch, #ιf 'XVT_OS_ISUNIX int asked = 0; mt text; ♦endif if ( xvt_dm_post_ask("Yes" , "No" .NULL, "Can't display this file. Attempt to save it locally'" )==RESP_2 ) return 1; /" No special behavior for th s file, try to save it */ if ( url'=NULL 1 url = fsys_nametaιl(url) ; if ( url==NULL ) url = "ftp.ftp"; retry: xvt_res_get_str(Callback_Saveas,frmt,sizeof(fr t) ) , sprintf(buf, xvt_res_get_str(Callback_Saveaε, frmt,εizeof (frmt) ) /'"Save %.50ε as..."*/, url ), memset(tfε, 'NO' ,sizeof(fs) ) ; strcpy(fs.name,fsys_nametaιl ( (char *)url) ) , if ( fsys_badnaune(fs.name, fn_local) ) fsys_makegoodname(fs.name, fn_local) , xvt_fsys_get_default_dιr(tfs.dir) , strcpy(fs. ype, ""); if (xvt_dm_post_fιle_save(ifs, buf ) '= FL_OK ) return 1, callback.c Fri Mar 24 16:16:58 1995 9 xvt_fsys_fs_to_str(ifs,buf,sizeof(buf) ) ; ret = RESP_DEFAULT; if ( fsys_access(buf,XVT_FILE_ATTR_EXIST) ) { if ((ret = navι_dm_post_ask(General_Save/*"Save"*/, Callback_NewNa_me/*"NewNeune"*/, General_Cancel/*"Cancel"*/, Callback_Exιsts/*"Fιle %.20s already existε, save anyway'"*/, buf))==R ESP_2 ) goto retry,- CacheFlus lbuf) ; } if ( ret'= RESP_DEFAULT ) return 1; ♦if XVT_OS_ISUNIX fp2 = fopenlbuf, "w") ; fpl = fopenlflie, "r" ) ; ♦else if ( !pmatch("*/*",type) ) { asked = 1; text = (pmatch("text/" , type) '= (char *)NULL); } if ( !asked ) text = (navι_dm_post_ask(Callback_Text/*"Text"*/, Callback_Bιnary/*"Binary"*/,NULL_RID, Callback_IsText/*"Is this a text flie'"*/)==RESP_DEFAULT) ; asked = 1; if ( text ) { fp2 = fopenlbuf, "wt" ) ; fpl = fopenlfile, "rt") ,- } else { fp2 = fopen(buf, "wb") ; fpl = fopenlfile, "rb") ,- } ♦endif if I fp2==NULL ) ( fclose!fpl) ; if ( navι_dm_post_ask(Callback_TryAgaιn/*"Try Again"*/, General_Cancel/*"Cancel"*/, NULL_RID, Callback_NoWrιte/*"You do not have write acceεs to %.20s, try again'"*/, b uf)==RESP_DEFAULT ) goto retry; return 1; } while (!ch=getc( pl) ) >=E0F) putc(ch, fp2) ; fclose(fpl); fclose(fp2); fsys_setfilecreator(buf, (char *)type); return 1; } static mt viewerfor(const char 'type) { int l; ford = 0; disppt[i] .type '= (char *)0; i++) { if(strcmpttype, dispp [i] .type)==0) return i; ) return -1; ) static int Dispose(const char 'type, const char 'file, const char *url, t ot) { callback.c Fri Mar 24 16:16:58 1995 10 char buf[0x400] ; mt l; if ( ot.'=OPEN_SAVE ) { ford = 0; dispptd] .type '= (char *)0, ι++) { if(strcmpttype, disppt[1] .type)==0) { ♦if XVT_OS_ISUNIX extern int systemlconst char *),- sprintf{buf, "%ε %ε t", disppt[l] .cmd, file ) ; system(buf) ; return true; ♦else /* ' ' ! ' external viewerε for other machmeε' */ break; /* Well, try saving it */ ♦endif } ) } return DisposeSave(file,url,type) ; ) static mt Translate(struct cstr *rs,formctx *ctx,εtruct strandinfo *sι) { char buf[0x400] , char tempbuf[0x100] ; char "temp; mt 1,3; FILE "fp; char "file; char *url = (ctx->form ' ctx->form->URL . ctx->url), extern char 'mytmpnaun() , mt fgetc(FILE *) ,- l = ctx->open_type-OPEN_FILTERS; for (3=0; inputp [ ].type'=NULL; ++3 ), if ( ι>=3 ) return false; ♦if XVT_OS_ISUNIX temp = mytmpnam(tempbuf) ; file = RsForceFιle(rs) ; sprintf(buf, "%s %s %s", ιnputpt[ι].cmd, file, temp ), if ( system(buf)==0 ) { /* Success */ Page "page = PageFιnd(url, "", NULL, "") ; HtmlPage hpage; memset(ihpage, 'NO', sizeof(HtmlPage) ) ; hpage.url = copy(page->url) ; fp = fopenltemp, "r") ; FillHtmlPagelthpage, fgetc, fp) , fclose(fp); fsys_delete(temp) , TransferHPageToPage(ihpage,page,si,false) , ctx->vιew = _VιewAlterURL(ctx->vιew, page, ctx->anchor,ctx->newvιew,ctx) , fsyε_delete(flie) ; return true; ) fsys_delete(fιle) ; return false; ♦else /* ' ' ' ' Input translators for other machines' */ return false; ♦endif } static void Slurplmage(struct strandinfo "si,struct cstr *rs,formctx *ctx) { callback.c Fri Mar 24 16:16:58 1995 11 if(sι->statuε >= 200 tt sι->statuε <= 299 it pmatch( "image/" , ει->type) ) { if(pmatch!"image/gif" ,ει->type) ) ( long to = mιllιsec(); if (ctx->codec) { ctx->ιmage->ιmage = partιal_read_gιf (ctx->codec) , del_partιal_context(ctx->codec) ,- } else { ctx->image->ιmage = _xvt_ιmage_read_gιf(rs) , ) fulltime += millisec() - tO, ) else { char "file = RsForceFιle(rs) , dbg_pnntf("%d %s %s(%ld)Nn", sι->status. sι->type, file, sι->ειze) if(pmatch("image/3peg" ,ει->type) ) ctx->image->image = xvt_ιmage_read_ 3 peg(file) , else if(pmatch("image/x-xbitmap' ,ει->type)) ctx->ιmage->ιmage = navι_ιmage_read_xb (flie) , else { ctx->ιmage->ιmage = xvt_ιmage_read(file) ) ) } if (ctx->rs) RsClose(ctx->rs) , if ( ctx->ιmage->ιmage == (XVT_IMAGE)NULL II ctx->ιmage->ιmage == UnknownlmageI) ) ( ctx->image->image = Badlmage() , ctx->ιmage-_>-ιs_error = true, ) ctx->ιmage->readιn = true; if I IsVιew(ctx->vιew) it ctx->vιew->page tt 'ctx->noshow ) ( /* change the color map if this is the last image */ if ( 'CrudForVιew(ctx->vιew,dont_abort, (void *) ctx) ){ VιewStdMsg(ctx->vιew) , VιewResetCLUT(ctx->vιew) , /"ViewRedrawImages(ctx->vιew,ctx->ιmage) ;*/ } ViewShowImageLoad(ctx->vιew->page,ctx->image,ct ) , int copycallback(voιd *, int); static Crud *_copy(voιd "vctx) { struct copyctx "ctx = (struct copyctx *)vctx, return _QueueCrud(UpdateCrud(ctx->url, 0, Rsld(ctx->rs) ) , copycallback, vctx) ; ) int copycallback(void "vctx, int rid) { struct copyctx "ctx = vctx, struct strandinfo si; struct cstr "rs = RsOpenId(rιd, tsi), /* Only used to get status */ RsClose(rs) , if(si.status == 302 | | si.εtatus == 301) { ιf(ctx->url) myfree(ctx->url) , ctx->url = copy(si.type) , _copy(vctx) , return 0, } else if ( si.status == 401 ) { callback.c Fri Mar 24 16:16:58 1995 12 DoAuthDlg(ctx->toname, _copy, vctx); return 0; ) if ( sι.status<200 | | si.status>299 ) { navι_dm_post_error(Callback_CantWrιte/*"Can't write to %.60s"*/, ctx->toname) ; } else if ( ctx->doc'=NULL ) { DocPart "dp; dp = LookupDocPar (ctx->doc,ctx->toname) ; if ( dp==NULL ) { dp = newDocPart(ctx->doc,fsys_nametail (ctx->tonamel , ctx->oldtype,NULL) ; DocPoειtιon(ctx->doc,dp) ; ) if ( pmatch("text/html" ,ctx->oldtype) ) PageTickle(ctx->toname) ,- dp->exιsts = true; DocRedrawDP(ctx->doc,dp) ; ctx->doc->dιrty = true; } CacheFlush(ctx->toname) ,- dbg_pnntf("Copy URL done %sNn", ctx->url); myfree(ctx->tonaune) ; myfree(ctx->url) ,- myfree(ctx->oldtype) ; myfree(vctx) ; return 1; ) char "GetGoodNaune(char "toname. Document *doc) ( char na e[256] , buf[801, buf2[200], rnt l,- char "temp, "pt; char "goods = *0123456789_abcdefghi3klmnopqrstuvwxyz" , strcpy(name, fsys_nametaιl(toname) ) ; do { fsys_makegoodname(name,doc?doc->nametype:fn_local) ; 1 = 0; while ( doc'=NULL it LookupDocPart(doc,name) '=NULL ) { if ((temp = strchr(name, '.') )==NULL ) temp = name+strlen(name) ; if ( temp-name<8 ) { for ( pt=naune+strlen(name) ,- pt>=temp, --pt ) pt[l] = "pt; "temp = goods[i],- } else temp[-1] = goods[l] ; ++1 ; ) /*"%.60s is not a valid name here, replace it with"*/ sprintf (buf2,xvt_res_get_str(Callback_Badname,buf,sizeof(buf) ) , fsys_nametaιl(tonaune) ) ,- if ( !xvt_dm_post_strιng_prompt(buf2,naune,sizeo (name) ) ) return(NULL) ; ) while ( fsys_badname(name,doc'doc->nametype:fn_local) | | (doc'=NULL it LookupDocPart(doc,name) '=NULL )), temp = myalloc(strlen(toname)+strlen(name)+1) ; εtrcpyltemp,toname) ; strcpy(fsys_nametaιl (temp) ,name) , return temp; } callback.c Fri Mar 24 16:16:58 1995 13 static void DoCopylstruct strandinfo "si, struct cstr *rs,formctx *ctx) { static char "oldtype; lf ( oldtype!=NULL it ctx->fromclιp ) sι->type = copy(oldtype) ; else if ( ctx->toclιp ) oldcype = copy(sι->type) ; if ( sι->status<200 | | sι->status>299 ) { navι_dm_post_error(Callback_CantLoad/*"Can't read %.60s"*/, ctx->url), } else if ( ctx->doc!=NULL ii pmatch("application/x-navidoc" ,sι->type) ) { navι_dm_post_error(Callback_CantCopy/*"Can't copy this into a miniweb"*/), ) else { if ( fsys_badname(ctx->toname,ctx->doc'ctx->doc->nametype fn_local) ) { char "ret; if ( (ret = GetGoodName(ctx->toname,ctx->doc) ) '=NULL ) { return, } else ( myfree(ctx->toname) , ctx->toname = ret, ) } { struct copyctx *cctx = (struct copyctx *)myalloc (sizeof(struct copyctx)), cctx->doc = ctx->doc, cctx->url = copy(ctx->toname) ; cctx->toname = copy(ctx->toname) , cctx->oldtype = copy(sι->type) ; cctx->rs = RsOpenldtRsId(rs) ,0) , cctx->vιew = ctx->vιew, _copy( (void *)cctx), ) } } int XVT_CALLC0NV1 SaveStyle(STYLE "εtl, char "name, int εaveimages, εtruct document "doc, struct page "page) { struct copyctx "cctx = (struct copyctx *) myalloc(sizeof(struct copyctx)), struct cstr "ws; cctx->doc = doc; cctx->url = copy(name) , cctx->toname = copy(naune) ; cctx->oldtype = copy("application/x-naviεtyle" ) , ws = WsCreate(200, "application/x-navistyle" ) , DoSaveStyle(ws, name, stl, saveimages, doc), cctx->rs = RsOpenId(WsClose(ws) ,0) , _copy( (void *)cctx); return 1, ) static int ιmg_callback(voιd "vctx, int rid) { formctx "ctx = (formctx *)vctx, struct strandinfo si, struct cstr "rs = RsOpenId(rιd,tsι) , if ( 'ctx->rs) ctx->rε = rs; callback. c Fri Mar 24 16 : 16 :58 1995 14 if ( si . status >= 200 it si . status<=299 tt ctx->ιmage tt pmatch ( si type , " image/gi f " ) ) ( XVT_IMAGE xi ; long tO = millisec ( ) , i f I ' ctx-> codec ) { ctx->codec = make_partιal_contex (ctx->rs) , ) xi = partιal_read_gιf(ctx->codec) , parttime += millisec(} - tO; ιf(xι) { ctx->ιmage->ιmage = xi; VιewShowImageLoad(ctx->vιew->page,ctx->ιmage,ctx) , ) ) ιf(rs '= ctx->rε) RsClose(rs) , return 0, /* enable the STOP buttδn if there are any cruds (except those with context == ignore) queued for it */ void XVT_CALLCONVl AnySetStopButton(Vιew "view, void "ignore) { extern void AnyToggleStop(View *, int active), AnyToggleStoplview, CrudForViewfview, dont_abort, ignore) ) ; ) Crud *_QueueCrud(Crud "crud, int (*func)(voιd *,ιnt), void *ctx) { crud = QueueCrud(crud, func, ctx), if(func == form_callback) { formctx *fc = (formctx *)ctx; AnySetStopButton(fc->vιew, NULL), } return crud, } Crud "ReSubmit(void "vctx) { formctx "ctx = (formctx *)vctx; return _QueueCrud(RetneveCrud(ctx->url, ctx->form) , for-_callback, vctx), ) static Crud *ReDιe(voιd "vctx) { Page "page = (Page *) vctx; page->crud = _QueueCrud(RetrιeveCrud(page->url, NULL) , dyιng_reload_callback, vctx) , return page->crud; } int dyιng_reload_callback(voιd "vctx, int rid) { Page "page = (Page *) vctx, struct strandinfo si, struct cstr "rs = RsOpenId(rιd,tsi) , mt ret = 0; switch ( si.status ) { case 301: case 302- myfree(page->url) , callback. c Fri Mar 24 16 : 16 : 58 1995 15 page->url = copy ( si . type ) ; ReDie (vctx) ; break ,- case 401 : DoAuthDlg (page->url , ReDie , vctx) ; break ; default - ret = 1 ; page->crud = NULL, if ( pmatch("text/",si.type) ) PageFromStrand(rs, tsi, page->url, NULL, OPEN_DEFAULT) , else /" I don't know what to do here' Set the doc to no links' */,- if ( page->dyιng it page->doc ) { DocPart 'dp = LookupDocPart(page->doc, fsyε_nametaιl (page->url) ) ; if ( dp'=NULL ) dp->loaded = NULL, } if ( page->dyιng it page->vιewε==NULL ) PageRemove(page,NULL_WIN) , else page->dyιng = false, break,- } RsClose(rs) ; return re ; ) int form_callback(voιd 'vctx, int rid) { formctx *ctx = (formctx *)vctx; struct strandinfo si; struct cstr *rs = RsOpenldlrid,tsi) ; int success = 0; char frmt(80] , AnySetStopButton(ctx->vιew, ctx) ; switch(si.status) { case 204: if ( ctx->ιmage'=NULL ) { /'If we were looking for an inline image, but did not find it then*/ /* don't want to bring up a page saying that, we 3ust want to show*/ /* our bad image icon, and redraw */ ctx->ιmage->ιmage = Badlmage() ; ctx->ιmage->readιn = true, ctx->ιmage->readstarted = false, ViewShowImageLoad(ctx->vιew->page,ctx->ιmage,ctx), ) else if ( ctx->sheet ) { navι_dm_post_error(Style_CantRead/*"Cannot open %s for reading a style"*/, ctx ->url ) ,- StyleWasDeleted(ctx->sheet) ; ) ThιngSetMessage(ctx->vιew, xvt_res_get_εtr(Callback_HTTP204, frmt,sizeof (frmt) ) /"HTTP 204 No Response"*/), break,- case 301: case 302: /* redirection kludged with type overload */ if(ctx->form) { DelForm(ctx->form) , ctx->form = NULL, } else { if ( ctx->orιgurl==NULL ) callback. c Fri Mar 24 16 : 16 : 58 1995 16 ctx->orιgurl = ctx->url , else myfree (ctx->url ) , myfree ( ctx- >anchor ) , ctx->anchor = 0 , ) ctx->url = copy ( si . type ) ; { char * ; ιf((ρ = strchr(ctx->url, '♦')) ) ( *p++ = 'NO' ; ctx->anchor = copy(p) ; } } ReSubmit(vctx) , return 0; case 304- if ( IsVιew(ctx->vιew) tt ctx->vιew->page'=NULL it ctx->ιmage==NULL it 'ctx->vιew->page->readm ) ( VιewRedraw(ctx->vιew) , ctx->vιew->page->readιn = true, ctx->vιew->page->readstarted = true, ) return 0, case 401: DoAuthDlg(ctx->url ' ctx->url ctx->form->URL, ReSubmit, vctx), return 0, case 404 case 400- lf ( ctx->toname==NULL tt ctx->ιmage==NULL tt ctx->sheet==NULL tt (ctx->open_type==OPEN_DEFAULT | | ctx->open_type==OPEN_HTML) ii pmatch("text/html",guesε_suffix(ctx->url ' ctx->url ctx->form->URL) ) ) Document *doc = DocLookupContainsFile(ctx->url) , if ( doc==NULL it si.document ) doc = DocLooKupt (char *) si.document) , /* Don't do a DocSyncFmd a) Only create stuff we know about */ /* b) It'll go into an infinite loop */ if ( (si.modifyable it doc==NULL it 'fsys_badname(ctx->url,fn_lσcal) ) || (doc'=NULL tt ■fsys_badname(ctx->url,doc->nametype) ) ) { ιf( doc'=NULL it xvt_dm_post_ask("Yes" , "No",NULL, "%.50s does not exist Create it'", fsys_nametaιl (ctx->url) )==RESP_DEFAULT ) { /* Create the page for them */ FιllupNewPage(ctx,tsi) ; RsClose(rs) ; return 1, ) else if ( doc'=NULL ) { /* Linda says they have already been told page didn't */ /* exist, no need to bring up 404 page */ RsClose(rs) ,- return 1; ) ) } /* Fall through into the normal case */ default. if(si.naviserver tt ctx->url) { char *p = strstr(ctx->url, ".//") , ιf(p) { p = strchr(pmatch("://" ,p) , '/'), if(p) *p = 'NO', AddServer(ctx->url) ; if(P) callback.c Fri Mar 24 16:16:58 1995 17 *P = '/', } } dbg_prιntf("Content-Type: %sNn" , si.type), if ( ctx->toname'=NULL ) { DoCopy(tsι,rs,ctx) , } else if(ctx->ιmage) ( /* were we looking for an inline image' */ Slurplmage(tsi,rs,ctx) , dbg_prιntf("partial %ld usec, full %ld usecNn" , parttime, fulltime) , ) else if ( ctx->open_type==OPEN_DEFAULT ii (pmatch("application/x-navistyle",si type) | | pmatch! "application/SLA" ,sι.type) ) ) { /* stereo lithography''*/ char "file = RsForceFιle(rs) , char "url = (ctx->form ' ctx->form->URL ctx->urlr, STYLE "sheet = ctx->sheet, if ( sheet==NULL ) * sheet = LookupStyle(url, " " .NULL) , if ( sheet==NULL ) { sheet = CopyStyle(url,normalstyle,NULL_WIN) , ThmgSetMessage(ctx->vιew, "Style sheet loaded' ), } ReadStyle(flie,NULL_WIN,sheet,NULL) , StyleRefresh(sheet) , success = 1,- ) else if ( ctx->sheet'=NULL ) { navι_dm_post_error(Style_CantRead/*"Cannot open %s for reading a style"*/, ctx ->url ) , StyleWasDeleted(ctx->sheet) , } else if ( pmatch("image/",si.type) tt (ctx->open_type== OPEN_HTML | | (ctx->open_type==OPEN_DEFAULT it viewerforlεi type)==-l )) ) { char *url = (ctx->form ' ctx->form->URL ctx->url), Page "page; formctx newctx; page = Pagelmage(url,si.document) , me set(tnewctx, ' NO' ,sizeof(newctx) ) , newctx.image = ImageCreate(url, "".NULL) , newct .image->readstarted = newctx.image->readιn = true, newctx.view = _VιewAlterURL(ctx->vιew, page, ctx->anchor,ctx->newvιew,ctx) Slurplmage(tsi,rs,inewctx) , success = 1, } else ιf( ctx->open_type== 0PEN_HTML || ctx->open_type==OPEN_TEXT | | (ctx->open_type==OPEN_DEFAULT tt pmatch("text/' ,si type)) ) ( char "url = (ctx->form ' ctx->form->URL ctx->url), Page "page = PageFromStrand(rs, tsi, url, ctx->orιgurl ctx->open_type) , if ( 'ctx->vιew) ctx->vιew = page->cur_vιew, if ( 'ctx->noshow ) ctx->vιew = _VιewAlterURL(ctx->vιew, page, ctx->ancho ,ctx->newvιew,ctx) , if(page->docname it 'page->doc) OpenURL(page->docname, ctx->vιew, false, OPEN_DOCUMENT, true,page->url) , /* Linda doesn't want it displayed (nor do I)*/ success = 1, else if ( ctx->open_type==OPEN_DOCUMENT | | (ctx->open_type==OPEN_DEFAULT tt pmatch("application/x-navidoc" ,s .type) ) ) { char "url = (ctx->form ' ctx->form->URL ctx->url), Page "page = PageLookup(url, "", NULL), Document "doc = DocLookup(url) ; char "file = RsForceFιle(rs) , if ( doc==NULL ) doc = newDoc(url), DocReadfdoc, file) , callback.c Fri Mar 24 16:16:58 1995 18 doc->modιfyable = si modifyable, if ( 'ctx->noshow ) CreateDocWm(doc) , if ( page'=NULL ) PageDestroy(page) , DocSetLoaded(doc) , success = 1, ) else if ( ctx->open_type>=OPEN_FILTERS tt Translate(rs,ctx,iεi) ) { /* All done */, } else { if( 'ctx->noshow) ( dbg_prmtf(""""droppedNn" ) , Dispose(si.type, RsForceFile(rs) ,ctx->form'ctx->form->URL ctx->url, ctx->open_type) , /* unlink them sometime ' ' ' */ goto noclose, ) else if(si document) { char "url = ctx->form ' ctx->form->URL ctx->url, Document "doc = DocLookup( (char *)sι document) if (doc) { DocPart "dp = LookupDocPart (doc url), ιf('dp) { dp = newDocPar (doc, fsys_nametaιl (url) , (char *)ει.type, (Pa ge *)NULL) DocPosιtιon(doc,dp) , } dp->exιsts = true, if(strcmp(dp->conten ype,sι type) ) myfree(dp->contenttype) , dp->contenttype = copy(si type) ) DocRedrawDP(doc,dp) , ) break, ) RsClose(rs) , noclose if(ctx->form) DelForm(ctx->form) , if(ctx->url) myfree(ctx->url) , myfree(ctx->orιgurl) , if (ctx->toname) myfree(ctx->toname) , if(ctx->anchor) myfree (ctx->anchor) , if ( ctx->vιew' =NULL it ctx->vιew->tag==TAG_VIEW ti ctx==ctx->vιew->wmfo->pendιng_context ) ctx->vιew->wmfo->pendιng_context = NULL, myfree (vctx) , return success , ) struct crud "SubmitFormtFor " form, View "view, char *refered_by) ( formctx *fc = ( formctx " Imyalloc (sizeof ( ormctx) ) , struct crud "crud, fc->vιew = view, fc->form = form, crud = RetrieveCrud(NULL, form) , crud->refered_by = refered_by, callback. c Fri Mar 24 16 :16 :58 1995 19 return ) _QueueCrud ( crud, form_callback , fc ) ) ,- } static Crud * _SubmιtURL (char "url , View "view, int newview, int open_type , mt noshow, ch ar *refered_by) { char "pt ; formctx *fc = (formctx *(myalloc(sizeof(formctx) ) ,- struct crud 'crud; fc->vιew = view; fc->url = copy(url), fc->newvιew = newview; fc->open_type = open_type; fc->noshow = noshow; ιf((pt = strchr(fc->url, '♦')) ) ( fc->anchor = copy(pt+l), *pt = 'NO'; } crud = RetπeveCrud(fc->url,0) ,- crud->refered_by = refered_by; return _QueueCrud(crud, form_callback, fc) , 1 struct crud *OpenURL(char *url, View 'view, int newview, int open_type, int noshow, char * refered_by) ( Document "doc; Page "page; char "pt; dbg_pπnt ("SubmitURL %sNn", url); /" We can't 3ust reload stuff, we need to get the old page with its */ /" contentε because the user might have changed it */ if (( page = PageLookup(ur1, "", ULL) ) '=NULL ii (open_type==OPEN_DEFAULT || open_type==OPEN_HTML) ) { ιf((pt = strchr(url, • ♦')) ) ++pt; _VιewAlterURL(view,page.pt.newview,NULL) ; return! NULL ) ; } if ((doc = DocLookup(url) )==NULL || (open_type'=OPEN_DEFAULT tt open_type'=OPEN_DOCUMENT) ) return! _SubmιtURL(url, view, newview, open_type,noshow,refered_by) ) ; else if ( !noshow ) CreateDocWιn(doc) ; return( NULL ) ,- ) void SubmitURL(char "url. View "view, char *refered_by) { OpenURUurl,view, false,OPEN_DEFAULT, false, refered_by) , ) void ReloadURLlchar "url, View "view. Image "image) { Crud *crud; formctx *fc; crud = _SubmitURL(url, view, false, OPEN_DEFAULT, false,url) ; crud->reload = true; if ( image '= NULL ) { fc = (formctx *) (crud->ctx) ,- fc->ιmage = image; fc->codec = 0; fc->rs = 0; callback. c Fri Mar 24 16 :16 : 58 1995 20 crud->part = img_callback; ) } int deleteback lvoid 'vctx, int rid) ; static Crud *_delete (void *vctx) { char *url = ( char * ) vctx; return _QueueCrud (DeleteCrud (url ) , deleteback, vctx) ; ) int deleteback (void 'vctx, int rid) { char "url = (char * )vctx; struct strandinfo si; struct cstr "rs = RsOpenldirid, tsi); iftsi.status == 401) { DoAuthDlg(url, _delete, vctx); } else { Document "doc = DocLookup(url) ; Page "page = PageLookup(url,"" ,NULL) ; STYLE "style = Lookupstyle(ur1, "" .NULL) ; if(si.status == 205 || si.status == 200) ( PageWasDeleted(page) ,- DocWasDeleted(doc) ; StyleWaεDeleted(εtyle) ; if( !page ti !doc) { char "name = copy(url) ; * (fsys_nametail (name) ) = 'NO'; if((doc = DocLookup(name) ) ) { DocRemovePageNamefdoc, url) ; DocRedraw(doc) ; ) free(name) ; ) } else if (page | | doc) { /* this is probably better done by putting the message into the window from which the dialog was activated... */ char buf[80] ; ThingSetMessage( (page ? page->viewε : (View *)doc->docview) xvt_res_get_str(Callback_CntDelete,buf,sizeof(bu ) ) ) ; xvt_scr_beep( ) ; } ) RsClose(rs) ; return 0; Crud * DeleteURHchar *url) { char *ctx_url = copy(url) ; return _delete( (void *)ctx_url) ) void XVT_CALLC0NV1 _PageStartRead(Page "page,int show) { formctx *fc = (formctx *(myalloc(sizeof(formctx) ) ; page->readstarted = true; fc->view = page->cur_view; if ( fc->view==NULL it show ) /* Create a view to display messages in*/ callback.c Fri Mar 24 16:16:58 1995 21 fc->vιew = VιewFromWmdow(CreatePageWιn(page) ) , fc->url = copy(page->url) ,- fc->noshow = ishow; page->crud = _QueueCrud(RetneveCrud(page->url, 0) , form_callback, fc) ,- } Page * XVT_CALLC0NV1 _PageRead(Page "page) ( Page *pg; if ( !page->crud) _PageStartRead(page,true) ,- if ( !_SyncCrud(page->crud) ) return NULL; for ( pg=PageHead( ) ; pg'=NULL; pg = pg->next ) if ( pg==page ) return page; return NULL, ) void ImageReadm(Image 'image, View "view, int sync) { Crud 'crud; dbg_prιntf( "Image readin of %sNn", ιmage->url ); if ( !ιmage->readιn ) ( formctx *fc = (formctx *Imyalloc(sizeof(formctx) ) ,- image->readstarted = true; fc->vιew = view; fc->ιmage = image; fc->url = copydmage->url) , fc->codec = 0; fc->rs = 0; i f ( ValιdInCache dmage->url ) ) ( struct strandinfo si; struct cstr *rs - RεOpenldlCacheCheckFordmage->url,NULL, 0) ,iεi) , fc->noshow = isync; Slurplmage(isl,rs, fc) ; RsClose(rs) ; myfree(fc->url) ; myfree(fc) ; return; ) crud = RetneveCrud dmage->url , 0 ) ; crud->refered_by = (vιew ! =NULL) ?vιew->page->url : "NaviPresε Image Load" _QueueCrud ( crud , f orm_callback, fc ) ->part = ιmg_callback ; if ( sync ) _SyncCrud(crud) ; } ) void StyleReadm(STYLE 'sheet,View 'view,char *refered_by) { Crud "crud; if I !sheet->readstarted ) ( formctx *fc = (formctx *(myalloc(sizeof(formctx) ) ; sheet->readstarted = true; fc->url = copy(sheet->name) ; fc->sheet = sheet; fc->vιew = view; crud = RetrieveCrud(sheet->name,0) ; crud->refered_by = refered_by'=NULL?refered_by: v ew!=NULL'vιew->page->url: "NaviPress Load Style Map"; _QueueCrud(crud, form_callback, fc) ,- } } callback.c Fri Mar 24 16:16:58 1995 22 static mt XVT_CALLCONVl _CopyURLToFιle(char "url, char "filename,Document "doc. int to, int from) { formctx *fc = (formctx *)myalloc(εizeof (formctx) ) , dbg_prιntf ( "♦♦♦ CopyURLToFile %ε %sNn" , url, filename) , { Page "page = PageLookup(ur1, "" .NULL) , if(page) { dbg_pπntf ("#♦♦ intercepted ♦♦♦Nn"); myfree(fc) ; SaveAsHTML(page, filename, false, false, true, doc, (View *) (doc ' doc->docvιew • NULL) ) ; return 1; } ) fc->url = copylurl); fc->tonaune = copy(filename) ; fc->doc = doc; fc->toclιp = to; fc->fromclιp = from; _QueueCrud(RetrιeveCrud(url, NULL) , form_callback, fc) , return 1 ; } int XVT_CALLCONVl CopyURLToFile (char "url, char "filename,Document "docl { return _CopyURLToFile(url, filename,doc, false, false) ; } int XVT_CALLCONVl CopyURLToClιp(char "url,Document *doc) ( mt ret; char "filename = userdιr_flie( "clipflie" ) , ret = _CopyURLToFιle(url , filename,doc, rue, false) , myfree (filenaune) , return ret,- } int XVT_CALLCONVl CopyClipToFile(char " ile,Document *doc) { int ret; char "url = userdιr_file( "clipfile" ) ; ret = _CopyURLToFιle (url, file, doc, false, true) , • myfree(url) ; return ret,- } / ***/ static char 'CheckHlT tle (char 'buffer, int size, char "pt, struct cstr *rs) { char buf2 [100] , *pt2; t ch; RsReadC(rs) ; /* Ending > of the <H1> */ for ( pt2=buf2, ch = RsReadC(rs); ch!=E0F tt pt2<buf2+sιzeof (buf2 ) -1; ch = RsReadC(rs) ) { if ( ch=='< r ) { /* HTML element, skip it */ if ( (ch=RsReadC(rs))=='/ ' ii (ch=RsReadC(rs) ) =='H' ii (ch=RsReadC(rs) )=='l' it (ch=RsReadC(rs))=='>' ) break, while ( ch'='>' tt ch'=EOF ) ch = RsReadC(rs) ; callback.c Fri Mar 24 16:16:58 1995 23 ) else if ( navι_ιsspace(ch) ) *pt2++ = ' ' , else *pt2++ = ch, } *pt2 = 'NO' , if ( strncmp(buffer,buf2,pt-buffer) '=0 ) { if ( pt>buffer ti pt[-l]'=' ' ) *pt++ = ' ' , strncpyIpt,buf2,size- (pt-buffer) ) , pt[size- (pt-buffer)-l]=' NO' , pt += strlen(pt) , ) if ( pt>buffer it pt[-l]'=' ' ) *pt++ = ' ' , return( pt ) , ) /* Take a message out of an html response, and display it the status bar */ /* view may also be a docview */ static void deHTMLmsg(struct cstr "rs.View "view Page "page) { char buffer(lOO). "pt, int ch, for ( pt=buffer, ch = RsReadC(rs), ch'=EOF ti pt<buffer+sizeof(buffer)-1, ch = RsReadC <rs) ) { if ( ch=='<' ) { /* HTML element, skip it */ ch = RsReadC(rs) ; if ( ch=='H' ii (ch=RsReadC(rs) (=='1' ) { pt = CheckHlTιtle(buffer,εizeof(buffer) ,pt,rs) ) else { while ( ch'='>' ii ch'=EOF ) ch = RsReadC(rs), } ) else if ( navι_ιsspace(ch) ) *pt++ = ' ' , elεe *pt++ = ch, ) "pt = 'NO', if ( vιew==NULL tt page'=NULL ) for ( vιew=page->vιews , vιew ' =NULL it (View * ) xvt_vob 3 _get_data (vιew->w) ' =vιew view = vιew->nextseune ) , if ( vιew==NULL ) / * Ignore it , we ' re in a saveall dig , we ' ll report errors later * / , else ThmgSetMessage (view, buf fer 1 , ) / / mt pagesavebacklvoid *, mt) , Crud *_PageSave(voιd *vctx) { struct savectx *sc = (struct savectx 'Ivctx, if(sc->navιlιnk) { Desc d; εc->form = NewForml"" ,sc->url,0) , TransAppendFormFιeld(sc->form, NS_FORM_URL_KEY, sc->page->url, 0,0), d.auth = GetAuth(sc->url) , d form = sc->form, return _QueueCrud(UpdateCrud(NULL, id, Rsld(sc->rs) ) , callback.c Fri Mar 24 16:16:58 1995 24 pagesaveback, vctx) ; } return _QueueCrud(UpdateCrud(sc--url, 0, Rsld(sc->rs) ) , pagesaveback, vctx), ) int pagesaveback(void "vctx, int rid) { struct savectx "ctx = (struct savectx "Ivctx; struct strandinfo si, struct cstr "rs = RsOpenId(rιd,tsι) , if(si.status == 302 || si.status == 301) { if(ctx->url) myfree(ctx->url) ; ctx->url = copy(si.type) , _PageSave(ctx) ,- RsClose(rs) ; return 1; /* • ' ' ' Status' */ } else if(si.status == 401) ( DoAuthDlg(ctx->url, _PageSave, vctx); RsClose(rs) ,- return 1; /* ' ' ' ' Status' */ ) ιf(sι.status >= 200 ii si.status <= 299) { if(pmatch!"applica lon/x-navilinks" ,si.type) ) { DoNaviLinks(rs,ctx->vιew) , } else { iffsi.εtatus == 202) { char frmt[80] , CreatePageWm(PageFromStrandlrs, iεi, xvt_res_get_str(Callback_savereε, frmt,sizeof(frmt) ) /"""save resultε*"*/,NULL, OPEN_DEFAULT) ) , } else if ( IsVιew(ctx->vιew) ) { char buf[30] ; xvt_res_get_str(Callback_Saved,bu ,sizeof(buf) ) , ViewSetMessage(ctx->vιew,buf) ; ) PageWasSaved(ctx->page,ctx->url,ctx->vιew) , } ) else ( deHTMLmsg(rs,ctx->vιew,ctx->page) ; PageSaveFailed(ctx->page,ctx->vιew,ctx->url,ctx->navιlιnk,si status) ; } RsClose(rs) , RsClose(ctx->rs) ; ctx->page->saveas = false, if(ctx->url) myfree(ctx->url) ; if(ctx->form) DelForm(ctx->form) , myfree(vctx) ; return(si.status >= 200 it si.status <= 299), ) int PageSave(Page "page, char "url, int dobase, int sync,View "view, int nvl) { struct savectx *sc = (struct savectx *)myalloc(sizeof(struct savectx)), struct cstr "ws = WsCreate(200, "text/html"), Crud "crud; page->savesucceded = false, sc->page = page; sc->url = copy(url); sc->vιew = view, callback. c Fri Mar 24 16:16:58 1995 25 sc->dobaεe = dobase; εc->navιlιnk = n l; WritePage (εc->page, εc->dobaεe, (int (*) ()) WεPutC, ws) ,- sc->rs = RsOpenId(WsClose (ws) ,NULL) , crud = _ PageSave (sc) ; return (sync ' _SyncCrud(crud) : 0) ; ) /*******"*/ static int stat_data=0; static char savecontenttype[40] ,- static Crud *_InfoCrud(voιd "vctx), static mt ιnfo_callback( void "vctx, int rid ) ( struct strandinfo si, struct cstr "rs = RsOpenld(rid,tsi) , char "url = (char *)vctx; lflsi.εtatus == 302 || si.status == 301) { if(url) myfree(url) ,- _InfoCrud(url) , RεClose(rs) ; return 1, /* ' ' ' ' Status' */ } else ιf(sι.status == 401) { DoAuthDlg(url, _InfoCrud, vctx); RsClose(rs) ,- return 1, /* ' ' ' ' Status' */ } stat_data = (si . status> = 200 it si .εtatus<400) ,- εtrncpy (εavecontenttype, εi . type, εizeof (savecontenttype) ) , savecontenttype [sizeof (savecontenttype) -1) = ' NO ' ; RsClose(rs) , return 1 , ) static Crud *_InfoCrud(voιd "vctx) { char "url = (char *)vctx; Crud "crud = RetrieveCrudturl,0) ; crud->ιnfo = true; return(QueueCrud(crud,ιnfo_callback, (void *)url )),- } int XVT_CALLC0NV1 url_exιstε(char *url) { _SyncCrud(_InfoCrud(url) ) , return! stat_data ); ) char *XVT_CALLCONVl fsys_lookupεuffix(char *url) { _SyncCrud(_InfoCrud(url) ) ; return! savecontenttype j ; ) / ........«/ callback. c Fri Mar 24 16:16:58 1995 26 static Crud * docsave (void "vctx) { εtruct docsavectx "ctx = (struct docsavectx *)vctx; return _QueueCrud(UpdateCrud(ctx->url ,NULL,RsId(ctx->rs) ) , docsaveback,vctx) } int docsaveback(void "vctx, int rid) { struct docsavectx "ctx = (struct docsavectx "Ivctx; Document "doc = ctx->doc; struct strandinfo si; struct cstr "rs = RsOpenId(rid, iεi); char buffer [100] ; switch (si . status) { case 301: case 302: myfree)ctx->url) ,- ctx->url = copy(si . ype) ; docsave(vctx) ; RsClose(rs) ,- return 0,- case 401: DoAuthDlg(ctx->url , docsave, vctx); RsClose(rε) ; return 0; case 200: case 206: DocWasSaved(doc) ,- xvt_res_get_str (Doccache_Saved, buffer, sizeof (buffer) ) ; break; default: xvt_res_get_str (Doccache_SaveFail,buffer, sizeof (buffer) ) ; break; } if ( doc->docview! =NULL ) ThingSetMessage ( (View *) (doc->docview) , buffer) ; RsClose (rs) ; myfree(ctx->url) ; RsClose(ctx->rs) ; return doc->dirty == 0; } int QueueDocSave(Document "doc, char "where) { struct docsavectx "ctx = myalloc(sizeof (struct docsavectx) ) ; char "buf; struct cstr *ws; int sizebuf; if ( where==NULL ) where = doc->name; ctx->doc = doc; doc->savesucceded = false; buf = myalloc (sizebuf=strlen(where)+strlen(WEBLET_MARK) +30) ; fsys_build_name(where, WEBLET_MARK, buf, sizebuf) ,- ctx->url = buf; wε = WεCreate (200, "application/x-navidoc" ) ; DocWriteldoc, (int ( *) ( 1 JWsPutC, ws); ctx->rs = RsOpenld(WsCloselws) , 0) ; docsave( (void * ) ctx) ; return 0; callback.c Fri Mar 24 16:16:58 1995 27 struct pubctx { int bouncing : 1; int backcoπ at : 1; /* backwardε compatible to publish... */ Document "doc; char "url; DocPart "part; struct cstr "ws; DocView *dv; ); static mt sumuptvoid *c) { return ('(long *)c)++, } static int pubcallback(void *, Λit) ; static Crud "DoPubPart(struct pubctx "ctx, DocPart "dp) { Crud "crud; ifI !ctx->backcompat) { whιle(dp ti dp->loaded tt (dp->loaded->changed | | dp->loaded->new) ) dp = dp->another; } if ( (ctx->part = dp) ) { char 'buffer ; int sizebuf ; buffer = myalloc ( sιzebuf=strlen (ctx->doc->name ) +strlen (ctx->part->relurl ) +30 ) fsys_build_name (ctx->doc->naune, ctx->part->relurl , buf fer , sizebuf ) ; DocSetMessage(ctx->dv, buffer); crud = QueueCrud(RetrieveCrud(buffer, 0) , pubcallback, (void *)ctx); yfree(buffer) ; } else { long count = 0; DocWrιte(ctx->doc, sumup, tcount) ; WsPrιnt(ctx->ws, "Content-Name: %sNrNn" , WEBLET_MARK) ,- WsPrmt(ctx->ws, "Content-Type: application/x-navidocNrNn" ) ; WsPrmt(ctx->ws, "Content-Length: %ldNrNn" , count), WsPrmt(ctx->ws, "NrNn"); DocWrite(ctx->doc, lint (*)(voιd *))WsPutC, ctx->ws); DocSetMessage(ctx->dv, "Publishing..."),- crud = QueueCrud(UpdateCrudlctx->url, 0, WsClose(ctx->ws) ) , pubcallback, (void *)ctx); ctx->ws = 0; ) return crud; ) static Crud *_publish(void *vctx) { struct pubctx *ctx = (struct pubctx *)vctx; Crud 'crud; if(ctx->bouncing) { crud = QueueCrud(RetrιeveCrud(ctx->url, 0) , pubcallback, vctx) ; crud->info = true; } else if(!ctx->ws) { ctx->ws = WsCreate(200, "application/x-naviwad" ) ,- crud = DoPubPart(ctx, ctx->doc->firεt) ; } return crud; ) callback.c Fri Mar 24 16:16:58 1995 28 static int pubcallback(void "vctx, mt rid) { struct pubctx "ctx = (struct pubctx *)vctx, struct strandinfo si, struct cstr 'rs = RsOpenldlrid, tsi), ιf(sι.status == 401) ( DoAuthDlg(ctx->url, _publιsh, vctx), } else { if (ctx->bouncιng) { if(si.status == 302 || si.status == 301) ( myfree(ctx->url) , ctx->url = copy(si.type) ; _publιsh(vctx) , ) else { ctx->bouncιng = 0, DoPubPart(ctx ctx->doc->first) } ) else if(ctx->part) { ιf(sι.status == 200) { WsPrmt(ctx->ws, "Content-Name %sNrNn" ctx->part->relurl) WsPrmtfctx->ws "Content-Type- %sNrNn' , si type) WsPrin (ctx->ws, "Content-Length %ldNrNn", si.size), WsPrmt(ctx->ws, "NrNn"); whilelsi.size--) { WsPutC(ctx->ws, RsReadC(rε) ) , ) } DoPubPart(ctx, ctx->part->another) , } else if ( sι.status>=200 it si.εtatus<=299 ) { ctx->doc->dιrty = 0, ctx->doc->new = 0, if(ctx->backcompat) { ιf(sι.status == 202) CreatePageWin(PageFromStrand(rs,tsi, "'publishing metadata*" ,NULL,OPEN_DEFAULT) ) , ) else { DocRenaune(ctx->doc,ctx->url) , DaveDocSave(ctx->doc) ; } myfreeIctx->url) , myfree(vctx) ; ) else { /* Error' */ deHTMLmsg(rs, (View *) (ctκ->doc->docvιew) ,NULL) , ) } RsClose(rs) ; return 0,- ) int PublishDoc(Document *doc, char *url, int backcompat) { struct pubctx *dsc = (struct pubctx *)myalloc(sizeof(struct pubctx)),- dsc->bouncιng = 1; dsc->backcompat = backcompat, dsc->doc = doc; dsc->url = copy(url), dsc->part = (DocPart *)0, dsc->ws = WsCreate(200, "application/x-naviwad" 1 , dsc->dv = doc->docvιew, _publιsh( (void *)dεc), callback. c Fri Mar 24 16:16:58 1995 29 return 1 ; ) /.............♦.... static int browsecallback(void *, int); Crud ".Browse(void *vctx) { struct browsectx *ctx = (struct browεectx *)vctx; return QueueCrud(BrowεeCrud(ctx->url) , browsecallback, vctx), } static int browsecallbac (void 'vctx, int rid) ( struct browsectx *ctx = (struct browsectx *)vctx; εtruct strandinfo si; struct cstr "rs = RsOpenld(rid, iεi); if(εi.εtatuε == 401) { DoAuthDlg(ctx->url, .Browse, vctx); } else { ChooserDoBrowse(ctx->w, rs, tsi); myfree(ctx->url) ; myfree(ctx) ; } RsClose(rs) ; return 0; ) Crud "BrowseURLIchar "url, WINDOW w) { struct browsectx "ctx = (struct browsectx *) yalloc(sizeof (struct browsectx)); ctx->url = copy(url); ctx->w = w; return .Browse( (void *)ctx); doccache. c Mon Mar 20 10 : 15 : 41 1995 1 /* Copyright 1994-1995 NaviSoft , Inc . All rights reserved. */ ♦include <stdarg . h> ♦include <xvt .h> ♦include <εtatbar .h> ♦include "NaviPreε .h" ♦include <guesε.h> ♦include "func.h" ♦include "doc.h" ♦include "view.h" ♦include "str.h" ♦include "guess.h" ♦include "crud.h" ♦include "xlocal.h" ♦include "weblet.h" ♦include "chooser.h" ♦include "callback h" extern int mιmweb_flletype, static int foutchfvoid *ctx, int ch) { FILE *fp = ctx, returnI fputc(ch, fp) ) ; ) static mt εtroutdnt (*func) (/* "? */), void *ctx, char *εtr) { while ( *str ) if I (*func) (ctx, *str++)==EOF ) return( EOF ) ,- return! 0 ) ; ) static mt strprintf! mt ("func) I),void "ctx,char *frmt,...l { va_lιst ap; va_εtart(ap, frmt) ,- if ( func==foutch ) vfpnntf ( (FILE *) ctx, frmt,ap) ; else { char buffer[1024] , vsprintf (buffer,frmt,ap) , strout(func,ctx,buffer) , } va_end(ap) ; returnI 0 ) ,- ) int XVT_CALLCONVl DocWπte(Document "doc, int ("func) (/* ??? */), void *ctx) { DocPart "page; DocPartLink *pl; εtrout(func,ctx, "navidoc l.ONn"); /* Standard header */ strprintf(func,ctx, "graph=%dNn", doc->graph_type) , strprintf{func,ctx, "nametype=%dNn" , doc->naunetype) , strprintf(func,ctx, "tιtle=%sNn" , doc->tιtle?doc-> itle: "" ) ,- strprintf(func,ctx, "style=%sNn" , doc->style?doc->style: "" ) ,- εtrprintf(func,ctx, "template=%εNn" , doc->temρlate?doc->template "") ,- strout(func,ctx, "Pages:Nn" ) ; for ( page'=NULL; page=page->another ) ( if ( page->exιsts tt 'page->external ) ( strprintf(func,ctx, "N"%sN" Up=N"%sN" Style=N"%sN" Tιtle=N"%sN" %d" , page->relurl, page->up'=NULL?page->up->relurl: " " , page->style'=NULL?page->style->relurl: " " , page->tιtle'=NULL?page->tιtle- " " , doccacba.c Mon Mar 20 10:15:41 1995 2 page->exιsts) ,- if ( page->userplaced ) strprintf (func,ctx, " %d %dNn", page->bb.left , page->bb.top ) ; else strprintf ( func,ctx, " Nn" ) , ) } strout (func,ctx, "Ghostε : Nn" ) ,- for ( page=doc->first; page'=NULL; page=page->another ) { if ( !page->exιsts tt !page->external ) { strprintf (func. ctx, "N"%sN" Up=N"%sN" Style=N"%sN" Tιtle=N"%sN" %d" , page->relurl, page->up!=NULL?page->up->relurl : " " , page->style! =NULL?page->style->relurl : " " , page->tιtle'=NULL?page->tιtle: " " , page->exιsts) ; if ( page->userplaced ) strprintf ( func, ctx, " %d %dNn" , page->bb. lef , page->bb.top ) , else strprintf I func,ctx, " Nn" ) , ) } strout I func,ctx, "Refs . Nn" ) ,- for ( page'=NULL; page=page->another ) ( if I page->exιsts it !page->external ) { strprintf (func, ctx, "N "%sN "Nn" , page->relurl ) ; for ( pi = page->refers_to; pl'=NULL; pi = pl->next ) ( εtrprintf (func,ctx, "Nt%d N"%sN" Nn" , : 0) | pl->page->relurl) ; ) } ) return 1 ; } mt DocCommit (Document *doc) { DocPart "dp; for (dp = doc->fιrst; dp; dp = dp->another) { if (dp->loaded) ( Page "page = dp->loaded; if ( ! PageCommit (page, NULL)) return 0; if (page->dιsmιssed it page->noname) PageRemove(page,NULL_WIN) ; ) } if ( doc->dιrty ) QueueDocSave (doc,NULL1 ; return 1 ; ) void DocSaveX(Document "doc, char "where, mt pagestoo) ( DocPart "page, char buf [100] ; if ( doc->docvιew' =NULL ) statbar_set_tιtle(doc->docvιew->w, vt_res_get_εtr (Doccache.Saving, buf , sizeof (buf) ) /""Saving..."*/) , occacha.c Mon Mar 20 10: 15 :41 1995 3 / * Now save any dirty pages in the doc * / if ( pagestoo ) for ( page = doc- > first , page ' =NULL, page=page->another ) if ( page->loaded it ' page->extemal tt page->loaded->changed tt page->loaded->modιfyable 1 { char "buf , int sizebuf , lf( 'where) buf = page->loaded->url, else { buf = myalloc(sizebuf=strlen(where)+strlen(page->relurl)+30) fsys_buιld_name(where,page->relurl, buf, si'Sebuf), ) PageSave(page->loaded, buf, false false, (View *)doc->docvιew, false) if ( buf'=page->loaded->url ) myfree(buf) , ) /* Check if we have any outstanding reloads that need to complete */ /* to get the manifest into a good form */ for ( page = doc->fιrst, page'=NULL, page=page->another ) f ( page->loaded'=NULL it page->loaded->dyιng tt page->loaded->crud'=NULL ) _SyncCrud(page->loaded->crud) , /* then update the manifest */ QueueDocSave(doc, where) , ) void XVT_CALLC0NV1 DocDoSave(Document "doc, int pagestoo) { DocSaveX(doc, NULL, pagestoo), ) DocPart *XVT_CALLC0NV1 newDocPart(Document *doc char "name, char *type. Page *pg) { DocPart "page = (DocPart *) myalloc(sizeof(DocPart) ) , if ( fsys_ιn_dιr(name,doc->name) ) name = fsys.nametail(name) , page->relurl = copylnaune) , if ( type'=NULL ) page->contenttype = copy(type), /* Storage leak 1 ' ' ' */ else page->contenttype = copy(guess_suffιx(name) ) , page->loaded = pg, if ( pg'=NULL ) page->tιtle = copy(pg->tιtle) , page->exιsts = true; page->needsplacmg = true, page->needsdrawing = true, if ( fsys_ιs_url(name) || fsys.naunetail(name) '=name ) { page->exιsts = false, page->external = true, } if ( doc->last==NULL ) doc->fιrst = page, else doc->las ->another = page, doc->last = page, if ( doc->docvιew'=NULL it 'page->external 1 { if ( pmatch(page->contenttype, "text/html"11 { WINDOW first = xvt_wm_get_ctl(doc->docvιew->w,Doc__Fιrst) , doccache . c Mon Mar 20 10 : 15 : 41 1995 4 mt i,- = xvt_lιst_count_all(firεt) ; xvt_lιεt_add(firεt,ι,page->tιtle?page->tιtle:page->relurl) ,- ) } return(page) ; ) DocPart *XVT_CALLC0NV1 newCheckDocPart(Document "doc, char "name) { DocPart "page = newDocPart(doc,name,NULL,NULL) ,- page->exιεtε = false; return page; ) DocPartLink *XVT_CALLC0NV1 newDocPartLιnk(DocPart "page, DocPartLink "next, int fl, int ii , t bw, int fm, int bu) DocPartLink *pl = (DocPartLink *) myalloc(εizeof(DocPartLink) ) , pl->page = page; pl->next = next; pl->from_lιst = fl, pl->ιnlιned_ιmage = ii, pl->bothways = bw; pl->formlmk = fm; pl->needsdrawmg = true ; pl->tιcked = true; return( pi ) , ) DocPart *XVT_CALLC0NV1 LookupDocPart(Document "doc, char "name) { DocPart "page; char "pt; if I name==NULL ) returnI NULL ) ; /* Often we will be looking up fully qualified urls, but the docpart list */ /* has relative urls */ if I doc->name'=NULL it ! fsys_ιn_dιr(naune,doc->name) 1 { for ( e = page->another ) if rcmp(page->relurl.name)==0 ) || t strmatch(page->relurl,name)==0 )) return( page ) ; } else if ( doc->name!=NULL ) { pt = fsys.nametail (name) ; for I page=doc->first; page'=NULL; page = page->another ) f ( (doc->nametype==fn_posιx it strcmp(page->relurl,pt)==0 ) | | (doc->nametype'=fn_posιx it strmatch(page->relurl,pt)==0 )) return( page) ,- } return( NULL ) ; ) static void FillupUps(Document *doc) { DocPart "page, "up, char "name; for ( page=doc->first; page'=NULL; page = page->another ) ( if ( page->up'=NULL ) { name = (char *) page->up; if (( up = LookupDocPart(doc,name) )==NULL ) ( doccacbe.c Mon Mar 20 10:15:41 1995 5 up = newDocPart(doc,name,NULL,NULL) ,- up->exιεts = false; } myfree(name) ; page->up = up, page->upboth = DocPageRefersTo(up,page) , up->downs = newDocPartLmk(page,up->downs,0,0,0,0,up->upboth) ,- ) if ( page->style'=NULL ) { naune = (char *) page->style; if ( ( up = LookupDocPart(doc,name) )==NULL ) { up = newDocPart(doc,name,NULL,NULL) .- up->exιsts = false; ) myfree(name) ; page->εtyle = up; up->refered_by = newDocPartLιnk(page,up->refered_by, 0, 0, 0, 0, falεe) , ) ) } static void XVT_CALLC0NV1 ReadPage(FILE "fp, Document "doc, char "buffer) { DocPart "page, int exists; buffer[0]=' NO' ,- fscanf(fp, *%900["\"] ", buffer ); if (( page = LookupDocPart(doc,buffer))==NULL ) page = newDocPart(doc,buffer,NULL,NULL) , buffer[0]='NO' ; fscanf(fp, "N" Up=N"%900 l ' \" ] " , buffer ); if ( buffer[0] '='N0' ) page->up = (DocPart *) copy(buffer) ; buffer[0]='N0' ; fscanf(fp, "N" Style= "%900 [ Λ N"] " , buffer ), if ( buffer[0] '='N0' ) page->style = (DocPart *) copy(buffer) ; buffer[0]='NO' ; fscanf(fp, "N" Tιtle=\"%900 ["N" ] " , buffer ), if ( buffer[0] '='N0' ) page->tιtle = copy(buffer) ; if I fscanf(fp, "N" %d %d %d" , texists, tx, ty)==3 ) ( page->userplaced = true, page->bb.lef = x; page->bb.top = y, ) fscanf(fp, "Nn") ; page->exιsts = exists; page->contenttype = copy(guesε_suffιx(page->relurl) ) ,- ) static DocPart * XVT.CALLCONVl ReadRef(FILE "fp, Document "doc, DocPart "page, char "buffe r) { int flags, ch; DocPart "other; fscanf(fp, "%900[ Λ N"] ", buffer ),- if ( page==NULL | | strcmp(buffer,page->relurl)'=0 ) page = LookupDocPart(doc,buffer) ; if (< ch = fgetc(fp) )=='"' ) ch = fgetc(fp) ; while ( (ch = fgetc(fp) )==' t' ) { fscanf (fp, "%d "%900[ Λ " ] ' , tflags, buffer ), if ( page'=NULL ) { doccacha.c Mon Mar 20 10:15:41 1995 6 other = LookupDocPart(doc,buffer) , if ( other==NULL ) { other = newDocPart(doc,buffer,NULL,NULL) , other->exιsts = false; ) page->refers_to = newDocPartLink(other,page->refers_to, flagstl, (flagst2) '=0, (flagst4) '=0, (flagsiβ) '=0, (flagstl6) '=0) ; other->refered_by = newDocPartLιnk(page,other->refered_by, flagsil, (flagsi2) '=0, (flagsi ) !=0, Iflagsiδ) '=0, (flagsil6) '=0) ; ) if ( I ch = fgetc(fp) )=="" ) ch = f etc(fp) ; } ungetc(ch, fp) , if ( page==NULL ) return( NULL ) ; return! page->another ), } Document *XVT_CALLC0NV1 DocRead(Document *doc, char 'name) { DocPart *next,- FILE *fp; char buffer[1000] , mt ch, gt; fp = fopen(name, "r") , if ( fp==NULL ) returnI NULL ) ; if ( fgetslbuffer,sizeof(buffer) , fp)==NULL | | strcmp(buffer, "navidoc 1.0Nn")'=0 ) { fcloεe(fp) ; returnI (Document *) -1 ); ) if ( doc==NULL ) doc = newDoc(NULL) ,- fscanf(fp, "graph=%dNn" , tgt) ; doc->graph_type = gt; buffer10] = 'NO'; while ( isspace( (ch=fgetc(fp) ) ) ), ungetc(ch,fp) ,- if ( ch=='n' ) { int nametype; fscanf ( fp , "nametype=%d" , t naune type ) ; doc->nametype = naune type ; while ( isspacef (ch=fgetc(fp) ) ) ); ungetc(ch, fp) ; ) else doc->naunetype = fn_posιx; fscanf(fp, "tιtle=%[ Λ Nn] ", buffer) ,- if ( buffer[0] '='N0' ) doc->tιtle = copy(buffer) ; buffer[0] = 'NO'; fscanf(fp, "Nnstyle=%[ Λ Nn] " , buffer) ; if ( buffer[0] '='N0' ) doc->style = copy(buffer) , buffer[0] = 'NO'; fscanf(fp, "Nntemplate=%[ Λ Nn] " , buffer) ; if ( buffer[0] '='N0' ) doc->template = copy(buffer) ; fscanf (fp, "NnPages:Nn" ) ; while ( (ch=fgetc(fp) )==' " ' ) doccache.c Mon Mar 20 10:15:41 1995 7 ReadPageIfp,doc,buffer) , ungetc(ch, p) ; if ( ch=='G' ) { fscanf(fp, "Ghosts: Nn" ) ; while ( (ch=fgetc(fp) )==' " ' ) ReadPage(fp,doc,buffer) , ungetc(ch,fp) , } next = doc->fιrst; fscanf(fp, "Refs:Nn" ) ; while I (ch=fgetc(fp) ) !=EOF ) { next = ReadRef(fp,doc,next,buffer) , } FillupUps(doc) , fcloεe(fp) ; return( doc ) ; } mt docεlurp(voιd "ctx, struct cstr "rs, εtruct strandinfo *sι) { Document "doc = (Document *)ctx; Document *d, if(sι->status == 200) { char "file = RsForceFile(rs) ; /* Docs are directories, may have read directory fine and not gotten */ /* a doc */ if ( (d=DocRead(doc, file) )==NULL || d== (Document *) -! ) { doc->modιfyable = sι->mod fyable, DocVιewDoUserPlaced(doc) ; DocRedraw(doc) , doc->loadsucceded = true; ) } doc->dιrty = 0, return 1; ) static mt docback(voιd "ctx, int rid) { struct strandinfo si; struct cstr "rs = RsOpenldlrid, tsi), docslurp(ctx,rε,tsi) ; RsClose(rs) ,- return 1; } static Document "docs; Document * XVT.CALLCONV1 DocHead (void) I return( docs ) ; } Document "XVT.CALLCONVl newDoclchar "name) { Document "doc, extern char dιr_char; doc = myalloc(sizeof(Document)) , if ( name ) { char buffer(500], "pt, ch; fεys_get_absolute_name(name,buffer,sizeof(buffer) ) , pt = buffer+strlen(buffer)-1; ch = "pt; if ( (fsys_ιs_url(buffer) ii *pt=-'/') || ( ' fsys_ιs_url(buffer) tt *ρt==dιr_char )) doccache.c Mon Mar 20 10 : 15 : 41 1995 8 { "pt = ' N O ' ; } else i f ( fsys_urlcmp ( f sys_neunetail (buf er ) , WEBLET_MARK) ==0 ) { pt = f sys_nametail (buf fer ) - 1 ; ch = "pt ; "pt = ' N O ' ; } doc->name = copy(buffer) ,- "pt = ch; ) doc->next = docs; doc->graph_type = g_web; docε = doc; return( doc ) ,- ) static Document *XV _CALLCONVl _DocFind(char "url. View "view, t sync) ( Document "doc; char "pt, ch; Page "page; Crud "crud; extern char dιr_char; ifI iurl) return (Document *)0; /"url = fsys_get_absolute_name(url,buffer,sizeof(buffer) ),-*/ pt = url+strlen(url)-1; ch = "pt; if ( (fεyε_i8_url(url) tt *pt=='/') | | I !fεyε_ιε_url(url) tt *pt==dιr_char )) { "pt = 'NO' ; } else if ( fsys_urlcmp(fsyε_nametaιl (url) ,WEBLET_MARK1==0 ) { pt = fεyε_nametail (url)-1; ch = "pt; "pt = 'NO'; ) for I doc=docε; doc!=NULL; doc = doc->next ) if ( fεyε_ur1cmp(url,doc->name)==0 ) { "pt = ch; return doc , ) doc = newDoc(url); "pt = ch; QueueCrud( (crud = RetrieveCrudlurl,0) ),docback.doc) ; if ( εync ) { extern int printf(conεt char *,...); SyncCrudlcrud, (int (*)(voιd *1 Jprintf, "_DocFιnd" 1 ; if ( !doc->loadsucceded 1 { DocDestroy(doc) ; doc = NULL; ) } if ( doc!=NULL ) { for ( page = PageHeadl); page!=NULL; page=page->next ) if I page->docname!=NULL tt fsys_urlcmp(page->docname,doc->name)==0 ) page->doc = doc; ) return doc; } Document *XVT_CALLC0NV1 DocSyncFmd(char "url, View "view) { return! _DocFιnd(url.view,true) ) ; ) doccacba.c Mon Mar 20 10:15:41 1995 9 Document *XVT_CALLC0NV1 DocFromFilename(char "url, View "view) { char res [0x100] ; char anch[1] ; URLTranε(WEBLET_MARK,url,NULL,res,anch,sizeof(res) ,sizeof(anch) ) ,- return DocSyncFind(res,view) ; ) Document *XVT_CALLC0NV1 DocLookup(char *url) ( Document "doc; char "pt, ch; extern char dir.char; pt = url+strlen(url)-1; ch = *pt; if ( (fsys_is_url(url) ii "pt=='/'l || ( !fsys_ιs_url (url) it *pt==dir_char )) "pt = 'NO' ; } else if ( fsyε_urlcmpIfsys_nametail(url) ,WEBLET_MARK)==0 ) { pt = fsys_nametail(url)-1; ch = "pt; "pt = 'NO' ; } for ( doc=docs; doc!=NULL; doc = doc->next ) if ( fsys_urlcmp(url,doc->name)==0 ) { "pt = ch; return doc ; ) "pt = ch; return NULL; ) Document "XVT.CALLCONVl DocLookupContainsFile(char "urll { char "pt; Document "ret; url = copy(url) ; pt = fsys_nametail (url) ,- ret = NULL; if ( pt>strstr(url, "://")+3) ( "pt = 'NO',- ret = DocLookup(url) ; myfree(url) ; ) return ret; } int XVT.CALLCONVl DICnt(DocPartLink *dl) { int cnt=0; while ( dl!=NULL ) { dl=dl->next; ++cnt; } return! cnt ) ; ) void DocDestroy(Document *doc) { Document *d; if ( doc==docs ) docs = doc->next; else { doccache.c Mon Mar 20 10:15:41 1995 10 for ( d = docs; d'=NULL it d->next'=doc; d=d->next ), if ( d'=NULL ) d->next = doc->next; ) /* Should free up the Doc and all its bits */ myfree(doc) , ) void DocWasDeleted(Document *doc) { lf(doc) { DocPart "dp, *dn, for(dp = doc->fιrst; dp; dp = dn) { dn = dp->another; PageRemove(dp->loaded,NULL_WIN) ,- ) DocNukeView(doc1 , if ( doc==docs ) docs = doc->next; else { Document *d; for ( d = docs; d'=NULL tt d->next'=doc; d=d->next ) if ( d'=NULL ) d->next = doc->next, void DocDelete(w) WINDOW w; { Document "doc = ( (DocView *)xvt_vob 3 _get_data(w) )->doc, if ( navι_dm_post_ask(General_Cancel/*"Cancel"*/,Doccache_Delete/*"Delete"*/,NULL_RID, Doccache.DelMW/*"Delete MiniWeb and everything in it'"*/) '=RESP_2 ) return, DeleteURL(doc->name) ; } void XVT_CALLC0NV1 DocUniqueichar ""name) ( static char buf[0x10], int seq = 0; do { sprintf(buf, "MW%d" , ++seq) ; } while(fsys_exιεts(buf) || DocLookup(buf) ) , "name = buf; ) static void XVT.CALLCONVl MakeNewDocdnt withpage) { Document "doc; char "naune; DocUmque(tname) ,- doc = newDoc(name) ; doc->modifyable = true; doc->nametype = mιnιweb_filetype; if ( CreateDocWm(doc)==NULL_WIN ) { DocDestroy(doc) ; return; ) PublishDoc(doc, doc->name, false), f ( withpage ) { NPCrudRundown() ,- BuιldNewPage(doc) ; ) NPCrudRundown() ; doccacbe.c Mon Mar 20 10:15:41 1995 11 doc->new = true; void XVT_CALLCONVl BuildNewDocWithPage(void) { MakeNewDoc( rue) ; } void XVT.CALLCONVl BuildNewDoc(void) { MakeNewDoc(false) ; ) /*"""""/ void XVT.CALLCONVl DocWasSaved(Document *doc) { doc->dιrty = false; doc->savesucceded = true, doc->new = false,- DocDιrtCheck(doc) ; ) void DocDismiss(Document *doc) { ιf(doc->new it !doc->askedfordelete) DeleteURL(doc->name) ; /' we should be able to get rid of the doc itself, but for now we 3 ust avoid the SaveAll dialog... */ doc->new = false; doc->dιrty = false; ) void DocNukeView(Document *doc) { if(doc->docvιew1 { WINDOW w = doc->docvιew->w; doc->docvιew = NULL, /* isn't there a better thing' */ xvt_vob 3 _destroy(w) ; ) } void DaveDocSave(Document *doc) { DocPart 'dp; doc->savesucceded = false; for ( dp=doc->fιrst; dp'=NULL; dp=dp->another ) { if ( dp->loaded '= NULL ) { Page "page = dp->loaded; ιf(page->new | | page->changed) DeferAPageSave(page, page->new) ,- ) } QueueDocSaveIdoc, doc->name) ; ) int DocClose(Document *doc) { DocPart 'dp; int didsave = true; doccache.c Mon Mar 20 10:15:41 1995 12 doc->savesucceded = true; if I doc->fιrst==NULL ) { if ( doc->new | | doc->anydιrt ) { ret = navι_dm_post_ask(Doccache_Delete/"Delete*/ , General.Save/* "Save" */ ,General_Cancel , Callback_EmptyWeb/*"MιnιWeb %s is empty Delete it'"*/, doc->name) ; } else ( ret = navι_dm_post_ask(Doccache_Delete/"Delete*/ , General.Cancel,NULL_RID, Callback_EmptyWeb/""MιnιWeb %s is empty Delete it'"*/, doc->name) , if ( ret==RESP_2 ) ret = RESP_3 ; } if ( ret == RESP_DEFAULT) { DeleteURL(doc->name) ; return 1; } else if ( ret==RESP_3 ) { doc->askedfordelete = false; return 0; } else if ( doc->new ) { if I IDaveDocSaveAs (doc) ) return 0, } else if ( doc->anydιrt ) DaveDocSave(doc) ; } else ιf(doc->new) { switch ( navι_dm_post_ask(General_Save/* "Save" */ , General_DontSave/*"Don' t Save" */ , General.Cancel/* "Cancel" */ , Vιewcmd_Modιfιed/*"% .100s has been modified, save it'"*/, doc->name) ) { case RESP.DEFAULT: if ( !DaveDocSaveAs (doc) ) return 0; break; case RESP_2 : dιdsave=false; break; case RESP.3 : return 0, } } else { if (doc->anydιrt) DaveDocSave(doc) ; } ♦if 0 for(dp = doc->fιrst; dp; dp=dp->another) if (dp->loaded) PageCloεe (dp->loaded, NULL); ♦endif DeferedSaveRundown( ) ; NPCrudRundown( ) ; DocDirtCheck (doc) ; if ( didsave it (doc->anyd rt | | !doc->saveεucceded) ) ( /* Save failed */ /* Don't mt create_wιn = (doc->dιrty | | !doc->εavesucceded ), for (dp = doc->fιrst; dp; dp=dp->another) if ( dp->loaded' =NULL it (dp->loaded->changed | | 'dp->loaded->savesucceded) ) create.win = PageRaise (dp->loaded,create_wιn) ; if ( doc->dιrty | | !doc->savesucceded ) { if ( doc->docvιew! =NULL ) doceache.c Mon Mar 20 10:15:41 1995 13 navι_vob 3 _raιse(doc->docvιew->w) ; else CreateDocWιn(doc) ; } if ( xvt_dm_post_ask ( "Don' Close", "Close", NULL, "Save Failed' Close MiniWeb anyway' ") ==RESP_DEFAULT ) return 0; doc->anydιrt = false; doc->dιrty = false; } DocDismisε (doc) ; DocNukeVιew(doc) ; return 1 ; ) t DocSaveAll (void) { Document "doc, "next; NPCrudRundown)) , /* Wait for any outstanding deleteε to clean up */ for ( doc=docs; doc'=NULL, doc=next ) { next = doc->next, if ( 'DocClose(doc) ) return false; } return true; ) static void PageNewName(Page "page, char "dname, char "relurl) ( char "buffer,- mt sizebuf; buffer = myalloc (dnaune)+strlen(relurl)+30) ; fsys_buιld_naune(dname,relurl, buffer, sizebuf); myfree(page->url ), page->url = copy( buffer ) , myfree(buffer) ; } void DocRename(Document "doc,char "name) { DocPart "dp; char "oldnaune = doc->naune, /* switch over the doc */ doc->name = copy(name) ; /* and the docview */ if ( doc->docvιew'=NULL ) DocVιewFillupNaune(doc->docvιew) , /* a_nd all the opened pageε */ for ( dp=doc->first; dp'=NULL; dp=dp->another ) { if ! dp->loaded '= NULL ) { Page "page = dp->loaded, PageNewName(page,name,dp->relurl) , PageSetURL(page, rue) . ) ) if(doc->new) 'DeleteUR (oldname) ; myfree(oldnaune) ; ) struct webizer { doccache.c Mon Mar 20 10:15:41 1995 14 char "url, Document "doc,- DocPart "dp, ), static int webizepagecallback(void "vctx, int rid), static struct crud *_webιzepage(voιd "vctx) { struct webizer "ctx = (struct webizer *) vctx, char "buffer; int sizebuf, buffer = myalloc(sizebuf=strlen(ctx->doc->name)+strlen(ctx->dp->relurl)+30) , fsys_buιld_name(ctx->doc->name,ctx->dp->relurl,buffer,sizebuf) , myfree(ctx->url) ; ctx->url = copy(buffer) , myfree(buffer) ; return QueueCrud(RetrieveCrud(ctx->url, 01 , webizepagecallback, ctx), } static Page "WebizeGetPage(struct webizer "ctx, struct cstr *rε, struct strandinfo *psι) ( char "buffer, int sizebuf, Page "page; buffer = myalloc (ctx->doc->name)+strlen(ctx->dp->relurl)+30) , fsys_buιld_name(ctx->doc->name,c x->dp->relurl,buffer,sizeof(buffer) ) , page = PageFromStrand(rs,psi.buffer,NULL,OPEN_HTML) ; myfree(buffer) ; return page; ) static void Webizelnsert(εtruct webizer "ctx, struct cstr "rs, struct strandinfo *psι) { Page *page; DocPart "dp. if (psι->status == 200 tt pmatch("tex /html", pει->type) ) { page = WebizeGetPage(ctx,rs,psi) , page->doc = ctx->doc; ctx->dp->loaded = page, LinkSearchlpage,ctx->dp,ctx->doc) , for ( dp=ctx->dp->another; dp'=NULL it (dp->external | | dp->loaded'=NULL | | 'pmatch!dp->contenttype, "text/html")) , dp=dp->another ), if ( dp==NULL ) { /* We is done, chillins */ DocDιrtySave(ctx->doc) ,- DocReset(ctx->doc) , myfree(ctx) ; myfree!ctx->url) , ) else { ctx->dp = dp; _webιzepage(ctx) , ) ) ) static int webizepagecallback(void "vctx, mt rid) { struct webizer "ctx = (struct webizer "Ivctx, struct strandinfo si; struct cstr "rs = RsOpenld(rid, tsi), ιf(s .statuε == 401) { DoAuthDlg(ctx->url, _webιzepage, vctx), ) else { Webizelnser (ctx, rs, tsi); doccache . c Mon Mar 20 10 : 15 :41 1995 15 RsClose (rs) return 0 ; ) static Page "Lookup(Document "doc, DocPart "dp) ( char "buffer; int sizebuf; Page "page; buffer = myalloc (sizebuf=strlen(doc->name) +strlen(dρ->relurl ) +30) fsys_buιld_name (doc->name, dp->relurl , buffer, sizebuf) ; page = PageLookup(buffer,"" ,NULL) ; myfree (buffer) ,- return page, } static void WebizeThis (struct webizer "ctx, struct cstr "rs, struct strandinfo *psι) char buffer[0x200] ,- Document *doc, DocPart "dp, int externdoc, if (psι->status == 200 tt pmatch( "application/x-navibrowse" , psι->type) ) ( doc = newDoc (ctx->url) ; externdoc = fsys_ιs_url (ctx->url) , while(RsGetLine(rs, buffer, sizeof (buffer11 >= 0) { char "type = buffer,- char "name = strchr (buffer, ' '),- *name++ = ' NO' ,- ♦if XVT_OΞ_ISUNIX if (strcmp(name,WEBLET_MARK) ===== 0 | | strcmptname, ".' ) == 0 | | strcmplnaune, " .. " )==0 ) { ♦else if ( ( iexterndoc it strmatch(name,WEBLET.MARK) == 0) | | (externdoc ti strcmptname,WEBLET_MARK) == 0) | | strcmp(name, ".") == 0 | | strcmp(name, "..") ==0 ♦endif /* don't show doc.nvd' */ } else if (pmatch!type, "application/x-navidoc" ) == 0) /* Don't support docs inside of docs */ ) else if (pmatchltype, "application/x-navidir" ) == 0) { /* Don't support directories inside of docs */ ) else ( newDocPart(doc,naune,type,NULL) ,- ) } for ( dp'=NULL ; dp=dp->another 1 { if ( pmatch(dp->contenttype, "text/html " ) ) if ( dp!=doc->fιrst ) DocChangeFirst (doc,dp) ; break; } ) CreateDocWιn(doc) , if ( pmatch(dp->contenttype, "text/html" ) ) ! if (( dp->loaded = Lookup(doc,dp))'=NULL ) ( dp->loaded->doc = doc, DocInsertPart(doc,dp->relurl,dp->loaded) , doccacha.c Mon Mar 20 10:15:41 1995 16 for ( dp=doc->first,- dp'=NULL it (dp->external | | dp->loaded'=NULL !pmatch(dp->contenttype, "text/html" )) ; dp=dp->another ),- if ( dp'=NULL ) { ctx->doc = doc; ctx->dp = dp; _webιzepage(ctx) ; } DocDirtySave(doc) ; ) ) static t webizecallback(voιd "vctx, int rid) ,- static struct crud *_webιze(void "vctx) ( struct webizer "ctx = (struct webizer *) vctx; return QueueCrud(BrowseCrud(ctx->url) , webizecallback, ctx), } static int webizecallback(void "vctx, int rid) ( struct webizer "ctx = (struct webizer *)vctx, struct strandinfo si; struct cstr "rs = RsOpenldfrid, tsi), ιf(sι.status == 401) { DoAuthDlg(ctx->url, _webιze, vctx), ) else { WebizeThis (ctx, rs, tsi); myfree(ctx->url) ; ctx->url = NULL; /* ctx lives on' */ ) RsClose(rs) ; return 0; ) static int WebizerOk(void * 3 unk, char "url, struct chooserinfo "info) { struct webizer "ctx = (struct webizer *) myalloc(sizeof (εtruct webizer); if ( DocLookup(url) '=NULL ) { navι_dm_poεt_error(Doccache_AlreadyIn/*"Already in a miniweb"*/), return falεe, ) ctx->url = copy(url); return _webιze(ctx) !=NULL; } void XVT.CALLCONVl AnyWebizer(WINDOW w) { View *vιew = (View *) xvt_vob 3 _get_data(w) ; char *buf; buf = myalloc(500) ; buf[0]='NO' ; Chooselt(view,Doccache_Saveas,buf, 500,CHOOSER_WEBIZER,WebizerOk) , myfree(buf) ; ) DocPart *DocPartFromNaune(char *url) { Document *doc, doc = DocLookupContaιnsFιle(url) ; if ( doc==NULL ) return NULL; doccacha.c Mon Mar 20 10:15:41 1995 17 return LookupDocPart (doc, fsys_nametail (url) ) ,- docadit.c Mon Mar 20 10:15:50 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved. */ ♦include <xvt.h> ♦include "NaviPres.h" ♦include "func.h" ♦include "html.h" ♦include "view.h" ♦include "style.h" ♦include "doc.h" ♦include "chooser.h" ♦include <xlocal.h> ♦include <guess.h> int DoPageTaglterate (Page "page, int ("fund () , void "ctx. Selection *εel) , void DocGraphNewfDocument *doc); void DocDrawNewlDocument *doc) ; int _HTML_HasAttr (char "str, int len, int tag,char "output, int osize.char "name) , static void LinklnName (DocPart "dp, Document "doc, char "name, int inlist, int isimage, in t form) { char "pt, DocPart "ndp, DocPartLink *dl, int upboth=0; if ( doc->docvιew' =NULL tt doc->docvιew->selected==dp ) { HighlightDocPar (doc->docvιew,doc->docvιew->selected) , /* Clear selection */ doc->docvιew->selected = NULL, } if ( (pt=strrchr(name, '♦' ) ) ' =NULL ) "pt = 'NO' , if ( name[0]== ' NO' ) /"No filename if within itself*/ name = dp->relurl ; if ((ndp = LookupDocPar (doc,name) )==NULL ) ndp = newCheckDocPart (doc,name) , if ( pt'=NULL ) *pt = '♦' , for ( dl=dp->refers_to, dl'=NULL; dl = dl->next ) if I dl->page == ndp ) { /* Already linked to * / dl->tιcked = true, if ( inliεt ) dl->from_lιεt = true; if I isimage ) dl->ιnlιned_ιmage = true; if ( form ) dl->formlιnk = true; dl->needsdrawιng = true; return, } for I dl=ndp->refers_to; dl ' =NULL it dl->page ' =dp; dl = dl->next ) , if ( dl'=NULL ) { dl->bothways = true, dl->needsdrawing = true, ) if ( ndp->up==dp ) { upboth = true, ndp->upboth = true; ) DocSetDirty(doc) , dp->refers_to = newDocPartLιnk(ndp,dp->refers_to, inlist, isimage,dl ' =NULL, orm,upboth) , ndp->refered_by = newDocPartLιnk(dp,ndp->refered_by, inlist, isimage,dl ' =NULL, form.upbot h) if ( dp->loaded' =NULL ) dp-__loaded->lιnkschanged = true, docedit.c Mon Mar 20 10:15:50 1995 2 } struct findthingsctx { Document "doc; DocPart *dp; ); static int XVT.CALLCONVl pfindthings(Page "page, Para "para, t tag, mt taglen, char "ta gtext, void "vctx) ( struct findthingsctx "ctx = (struct f dthingsctx *) vctx, char buffer[300] , t inlist = 0; text,taglen, ag,buffer,sizeof(buffer) , "SRC") ) ,ctx->doc, buffer, false,true, false) , if ( _HTML_HasAttr(tagtext, taglen,tag,buf er,sizeof(buffer) "HREF")) { while ( para'=NULL ti 'inlist ) { if ( para->tag==UL_TAG | | para->tag==OL_TAG | | para->tag ==DL_TAG ) inlist = true, para = para->ρarent, } LinklnName(ctx->dp,ctx->doc, buffer,inlist, false, false) , ) } else if ( tag==FORM_TAG ) { if ( _HTML_HasAttr(tagtext,taglen,tag,buffer,εizeof(buffer) "ACTION")) LinklnName(ctx->dp,ctx->doc, buffer,falεe, false,true) , } return( 1 ) , } static DocPartLink "ReverseList(DocPartLink *dl) ( DocPartLink "prev, "ndl, prev = NULL; while ( dl'=NULL ) ( ndl = dl->next, dl->next = prev, prev = dl,- dl = ndl; } return(prev) ; ) void LιnkSearch(Page "page, DocPart "dp. Document *doc) { DocPart "ndp; εtruct fmdthingsctx ctx, if ( page->upl '=NULL ) { if (( ndp = LookupDocPart(doc,page->upl) )==NULL 1 ndp = newCheckDocPart(doc,page->upl) , if ( dp->up'=ndp 1 { dp->up = ndp, ndp->downs = newDocPartLιnk(dp,ndp->downs,0,0,0,0,0) , ) ) elεe dp->up = NULL, if ( page->style'=NULL it ' fsys_ιε_url (page->style) ) { if (( ndp = LookupDocPart(doc,page->style) )==NULL ) ndp = newCheckDocPar (doc,page->style) , if ( dp->style'=ndp ) { dρ->style = ndp, ndp->refered_by = newDocPartLιnk(dp,ndp->refered_by, 0, 0, 0, 0,0) , docadit .c Mon Mar 20 10 : 15 : 50 1995 3 } ) else dp->style = NULL, ctx doc = doc, ctx dp = dp, DoPageTaglterate(page,pfindthings,tctx.NULL) , dp->refers_to = ReverseList(dp->refers_to) , ) DocPart *XVT_CALLC0NV1 DocInεertPart(Document "doc, char "name, Page "page) { DocPart "docpart, docpart = LookupDocPart(doc,name) , if ( docpart'=NULL it docpart->exιsts ) { DocRemovePart(doc,docpart, false) , docpart = LookupDocPart(doc,name) , /* Might be links to it, so may still exis t */ ) if ( docpar ==NULL ) docpart = newDocPart(doc,name,NULL,page) else docpart->loaded " = page, docpart->exιstε = true, docpart->needsdrawιng = true /* It might have been a ghost, still redraw */ myfree(docpart->tιtle) , if ( page'=NULL ) { docpart->tιtle = copy(page->tιtle) , if ( doc->fιrst'=NULL it doc->fιrst->loaded==NULL tt 'pmatch!"text/html",doc->first->contenttype) ) DocChangeFirst(doc,docpart) , else if ( doc->docvιew'=NULL ) DocViewFillupFirst(doc->docvιew->w) , } if ( page'=NULL tt 'docpart->external ) ( LinkSearch(page,docpart,doc) , } returnf docpart ), ) void XVT_CALLC0NV1 DocAddPage(Document "doc Page "page, char "nametail int saveimages l nt fullurl) { int ret, sizebuf, char "buffer ntbuf[100], "nt, if < saveιmages==-l ) { saveimages = 0; if(DocLookupContaιnsFιle(page->url) '= doc) { if ( fullurl==-l ) saveimages = DoImportOptions(tfullurl) , else { ret = navι_dm_post_ask(Docedιt_SaveLocal/*"Save Local"*/ Docedιt_SaveAll/*"Save All"*/, Docedιt_Page/*"Only Page"*/, Docedιt_InsInl/*"Insert mimed images as well as the page'"*/), if ( ret==RESP_DEFAULT ) saveimages = 1 else if I ret==RESP_2 ) saveimages = 2 ) ) ) if ( fullurl==-l ) ful lurl = false , i f I nametaιl==NULL ) naunetail = page->url , nt = fsys _makerealname ( nametail , ntbuf , sizeof (ntbuf ) , doc->nametype ) , docadit.c Mon Mar 20 10:15:50 1995 4 buffer = myalloc (doc->name)+strlen(nt)+30) ; if ( 'pmatch! "text/html" ,guesε_suffix(nametail)) ) { char "pt; fsys_buιld_name(doc->name,nt,buffer,sizebuf) ,- pt = strchr(fsys_nametaιl (buffer) ,'.') , if ( pt==NULL ) pt = buffer+strlen(buffer) , if ( doc->nametype==fn_doε ) strcpy(pt, " .htm" ) , else strcpy(pt, " .html") ; } else fsys_buιld_name(doc->name,nt,buffer,sizebuf) ,- if ( fsys_badname(buffer,doc->na_metype) ) fsys_makegoodnaune(buffer,doc->nametype) ; if ( strcmp(page->url.buffer) '=0 ) { SaveAsHTML(page,buffer,saveimages, fullurl, false, doc, (View ") (doc->docvιew) ) ,- ) myfree(buffer) ,- } void DocInsertPage(Document "doc, Page "page, char "name) { char "buf, int sizebuf; page->docname = copy(doc->name) ; page->doc = doc, buf = myalloc(sizebuf=strlen(doc->name)+strlen(name)+30) , • fsys_buιld_name(doc->name,name,buf,sizebuf) ; myfree(page->url) ; page->url = copy(buf) ; PageSetURLIpage,true) ; page->modι yable = true, DocInsertPart(doc, name, page), DocGraphNew(doc) , DocDrawNew(doc) , DocSetDirty(doc) , myfree(buf) ; } void XVT_CALLC0NV1 DocAddPageName(Document "doc, char "name, int saveimages, int fullurl) { char "buffer, ntbuf[100]; Page "page, DocPart "dp; char "conflict; int done, sizebuf, buffer = myalloc(sizebuf = strlen(name)+strlen(doc->name)+30) ; fsys_buιld_name(doc->name, fsys_makerealname(naune,ntbuf,sizeof(ntbuf) ,doc->nametype) , buffer,sizebuf) ; if ( fsys_badname(buffer,doc->naunetype) ) fsys_makegoodnaune(buffer,doc->nametype) ; conflict = buffer; if ( (dp = LookupDocPart(doc, fsys_nametaιl(buffer) ))'=NULL ti dp->exιsts ) { if ( CopyURLIsThiε(doc->naune, fsys_nametaιl(buffer) ) ) { char "title; PageUnique(tconflict, ttitle, doc); ) else { docβdit . c Mon Mar 20 10 : 15 : 50 1995 5 i f ( navι_dm_post_ask (General_Save/ * " Save " * / , General_Cancel / * "Cancel " * / , ULL_RID, Vιewsave_Exιsts/ * " Fιle % 100s already exists , save anyway' " * ' , fsys_nametaιl (buffer ) ) ' = RESP_DEFAULT ) return; ) ) done = false ; page=PageLookup(name, "" ,NULL) ,- f ( pmatch("text/html",guess_suffιx(naune) ) it page==NULL ) page = PageSyncFind(naune, "" .NULL,NULL) ; else if ( pmatch("*/*",guess_suffιx(name) ) tt page==NULL it pmatch!"text/html" , fsys_lookupsuffιx(name) 1 1 /* Deal with stuff like ht tp: //navisoft.com/ */ page = PageSyncFind(naune, "" ,NULL,NULL) , /* No obviouε content type */ if ( page'=NULL it !page->orthodata ) { DocAddPage(doc,page,conflict,saveimages, fullurl) , ) else if ( page'=NULL ) { xvt_dm_post_error("This doesn't exist, can't add it to MiniWeb" ) ) else ( if ( ' fsys_ιs_url(name) ) { conflict = copy(buffer) ; fsys_get_absolute_name(name,buffer,sizebuf) , name = buffer; ) if ( strcmp(conflict,name)==0 ) { DocInsertPart(doc, fsys_nametaιl(name) ,NULL) DocGraphNew(doc) ; DocDrawNew(doc) ; DocSetDιrty(doc) ; ) else if ( pmatchf"application/x-navimap" ,guess_suffix(name) ) ) { CopyMapToMaplname,conflict,false.doc) ; } else { CopyURLToFile(name,conflict.doc) , ) if ( conflict'=buffer) my ree(conflict) , } myfree(buffer) , } void XVT_CALLCONVl DocAddMapFile(Document *doc, char 'name, int rent, char "urls, char 'defurl ) { DocPart *dp, *ndp; DocPartLink *dl; int i ; char *pt; DocAddPageNaune(doc,name, -1, -1) ,- dp = LookupDocPart(docnaune) ; for ( ι=0, ι<rcnt; ++ι ) { if ( ( pt = strrchr(urls[I] , '♦' 1 ) '=NULL ) *pt = 'NO'; if (( ndp = LookupDocPart(doc,urls[l] ) )==NULL ) ndp = newCheckDocPart(doc,urIs[i] ) ,- if ( pt!=NULL ) 'pt = '♦' , for ( dl=dp->refers_to; dl'=NULL it dl->page'=ndp; dl = dl->next ) ; if ( dl==NULL ) { for ( dl=ndp->refers_to; dl'=NULL it dl->page'=dp; dl = dl->next ), if ( dl!=NULL ) dl->bothways = true; dp->refers_to = newDocPartLιnk(ndp,dp->refers_to, false, false, dl'=NULL, false,false) ; ndp->refered_by = newDocPartLmk(dp,ndp->refered_by, 0, 0,dl'=NULL, 0, 0) , docadit .c Mon Mar 20 10: 15:50 1995 6 ) } if ( defurl '= NULL it "defurl '='N0' ) { if ( { pt = strrchr(defurl, '♦')) !=NULL ) "pt = 'NO',- if (( ndp = LookupDocPart(doc,defurl) )==NULL ) ndp = newCheckDocPart(doc,defurl) ; if ( pt!=NULL ) "pt = '♦' ; for ( dl=dp->refers_to; dl!=NULL tt dl->page!=ndp; dl = dl->next 1; if ( dl==NULL ) { for ( dl=ndp->referε_to; dl'=NULL it dl->page'=dp; dl = dl->next ) ; if ( dl!=NULL ) dl->bothwayε = true; dp->refers_to = newDocPartLink(ndp,dp->referε_to,falεe, falεe, dl!=NULL, false,false) ; ndp->refered_by = newDocPartLιnk(dp,ndp->refered_by, 0, 0,dl '=NULL, 0, 0) ; } ) DocGraphNew(doc) ; DocDrawNew(doc) ; ) static void XVT_CALLC0NV1 RemoveBackLinkPagelDocument "doc, DocPart "dp, DocPart "gone) { DocPartLink "sdl, "pdl; if ( dp->refered_by!=NULL tt dp->refered_by->page==gone ) ( sdl = dp->refered_by; dp->refered_by = sdl->next; if ( dp->refered_by==NULL ti dp->downs==NULL tt 'dp->exιstε ) DocRemovePart(doc,dp, true) ; myfree(sdl) ; ) else if ( dp->refered_by'=NULL ) { pdl = dp->refered_by; for ( sdl = pdl->next; sdl'=NULL ti sdl->page'=gone; sdl = sdl->next ) pdl = sdl; if ( sdl!=NULL ) { pdl->next = sdl->next,- myfree(sdl) ; > } if ( dp->style == gone ) dp->style = NULL; } static void XVT_CALLC0NV1 RemoveBackLm (Document "doc, DocPartLink "dl, DocPart "gone) { DocPart "dp = dl->page; DocPartLink "sdl; if ( dl->bothways ) { for ( sdl=dp->refers_to; sdl!=NULL; sdl=sdl->next ) if ( sdl->page == gone ) sdl->bothways = false; } RemoveBackLinkPage(doc,dp,gone) ,- myfreeldl) ,- ) static void XVT_CALLC0NV1 RemoveDown(Document "doc, DocPart "dp, DocPart "gone) { DocPartLink "dl, "pdl; if ( dp->downs!=NULL it dp->refered_by->page==gone ) { dl = dp->downs; dp->downε = dl->next; if ( dp->refered_by==NULL tt dp->downs==NULL tt !dp->exιsts ) docadit .c Mon Mar 20 10 : 15 : 50 1995 7 DocRemovePart ( oc , p , true ) ; myfree ( dl ) ; ) else if ( dp->refered_by! =NULL ) { pdl = dp->downs ; for ( dl = pdl ->next ; dl ! =NULL tt dl->page ! =gone; dl = dl->next ) pdl = dl ; i f ( dl ! =NULL ) { pdl->next = dl->next; myfree(dl) ; ) } ) void XVT_CALLCONVl DocRemovePageName(Document "doc, char "name) { DocPart 'dp = LookupDocPart(doc,name) ; if ( dp it dp->exists ) DocRemovePart(doc,dp,true) ,- } void XVT_CALLC0NV1 DocRemovePart(Document *doc, DocPart "dp, int rm) ( DocPartLink "ndl, "dl; DocPart "ndp, "pdp; for ( dl = dp->refers_to; dl!=NULL; dl=ndl ) { ndl = dl->next; RemoveBackLink(doc,dl,dp) ; } dp->refers_to = NULL; if ( dp->up!=NULL ) RemoveDown(doc,dp->up,dp1 ; if ( dp->style!=NULL ) RemoveBackLinkPage(doc,dp->style,dp) ; dp->exists = false; if ( dp->downs==NULL it dp->refered_by==NULL it !dp->exists it r ) { if ( doc->first == dp ) { doc->first = dp->another; if ( doc->last==dp ) doc->last = NULL; ) else ( pdp = doc->first; for ( ndp=pdp->another; ndp!=dp tt ndp!=NULL; ndp = ndp->another ) pdp = ndp; if ( ndp==dp ) pdp->another = dp->another; if ( doc->last == dp ) doc->last = pdp; } if ( doc->docview!=NULL tt doc->docview->selected==dp ) { HighlightDocPart(doc->docview,doc->docview->selected) ; doc->docview->selected = NULL; J ) DocSetDirty(doc) ; if ( doc->docview!=NULL ) DocViewFillupFirst(doc->docview->w) ; ) /* Someone deleted an anchor out of this page. We need to keep track of who */ /* links whom */ void XVT_CALLC0NV1 DocPageLostLink(Page 'page, char "linkname) { DocPart "dp; char buf[60] ,- if ( page->docname!=NULL ) { docadit.c Mon Mar 20 10:15:50 1995 8 if ( page->doc==NULL ) { if ( page->vιews'=NULL 1 ViewSetMessage(page->vιews,xvt_reε_get_str(Docedιt_Loadιng,buf,sizeof (buf) ) /*"Loading miniweb "*/) , page->doc = DocSyncFmd(page->docname,page->vιews) ; if ( page->vιews'=NULL ) ViewSetMessage(page-> iews, "" ) , } if ( page->doc'=NULL tt (dp=LookupDocPart(page->doc,page->url) ) '=NULL ) dp->out_of_date = true, ) } void XVT_CALLC0NV1 DocPageLostlmageLink(Page "page, char "imagename) ( DocPageLostLinklpage, imagename) , } /* The text in the selection changed If there are any links/images in there */ /* or if the document is marked out of date, then we need to refigure some */ /* stuff */ void XVT_CALLCONVl DocLmkCheck(Page "page, Selection *sel) { DocPart "dp, struct fmdthingsctx ctx, DocPartLink *pl, "prev, "pn; int update = false, if ( page->docname==NULL ) return, page->doc = DocLookup(page->docname) , if ( page->doc'=NULL ti (αp=LookupDocPart(page->doc,page->url) ) '=NULL it (dp->out_of_date | | sel==NULL ) ) { for ( pi = dp->refers_to; pl'=NULL, pl=pl->next ) pl->tιcked = false, ctx.doc = page->doc, ctx dp = dp; DoPageTaglterate(page,pfindthings,tctx,NULL) for ( pi = dp->refers_to, prev=NULL; pl'=NULL, pl=pn ) ( pn = pl->next, if I 'pl->tιcked ) { if { prev==NULL ) dp->refers_to = pn, else prev->next = pn, page->lιnkschanged = true; RemoveBackLιnk(page->doc,pl,dp) , update = true, ) else prev = pi; } if ( update ) { DocRedraw(page->doc) ; DocSetDιrty(page->doc) , } else { DocGraρhNew(page->doc) , DocDrawNew(page->doc) ; ) dp->out_of_date = false, ) else if ( page->doc'=NULL ii dp'=NULL it sel'=NULL ) { ctx.doc = page->doc, ctx.dp = dp, DoPageTaglterate(page, findthings,tctx,sel) , docadit.c Mon Mar 20 10:15:50 1995 DocGraphNew(page->doc) , DocDrawNew(page->doc) ; void DocFormChecktPage "page, ara "para) { DocPart "dp; if ( page->docname==NULL | | para->tag'=F0RM_TAG ) return; if ( page->doc==NULL ) page->doc = DocLookup(page->docname) ; if ( page->doc'=NULL tt (dp=LookupDocPart(page->doc,page->url) ) '=NULL ) ( dp->out_of_date = true; DocLinkCheck(page,NULL) ; ) void XVT_CALLC0NV1 DocCopyURL(WINDOW w) ( DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , char "buffer, int sizebuf, if ( dv->selected==NULL ) { CopyUrlAdd( (struct view *)dv,dv->doc->name,dv->doc->tιtle,false) ,- } else if ( dv->selected->loaded'=NULL tt dv->selected->loaded->noname ) { navι_dm_post_message(Docedιt_UnrealName/*"Page does not have a real name Please S ave it"*/ ) ; } else if ( dv->selected->extemal) { CopyUrlAdd( (εtruct view *)dv,dv->εelected->relurl,dv->selected->tι le, falεe) , } else ( buffer = myalloc(sizebuf=strlen(dv->doc->name)+strlen(dv->selected->relurl)+30) , fsys_buιld_name(dv->doc->name,dv->εelected->relurl.buffer,sizebuf) , CopyUrlAdd( (struct view *)dv,buffer,dv->selected->tιtle, false) , myfree(buffer) ,- > } /**""""****/ void XVT_CALLC0NV1 DocClear(WINDOW w) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ; char "buffer; int sizebuf; if ( dv->selected==NULL ) xvt_scr_beep() ; else if (dv->selected->external) xvt_scr_beep() ; else { if ( dv->selected->loaded'=NULL it dv->selected->loaded->changed ) ( if ( xvt_dm_post_askI"Cancel", "Delete",NULL, "This item has been modified, delete it anyway'" 1==RESP_DEFAULT 1 return; ) buffer = myallocIsizebuf=strlen(dv->doc->name)+strlen(dv->selected->relurl)+30) fsys_buιld_na_me(dv->doc->name,dv->selected->relurl, buffer,sizebuf1 ; if ( CopyURLIsThis(dv->doc->name,dv->selected->relurl) ) ( CopyUrlAdd(NULL,buffer,dv->selected->tιtle, rue) ; CopyURLToCliplbuffer,NULL) ; ) /* If it is not loaded, then it must be on disk, so we must be able */ /* to delete it */ docβdit.c Mon Mar 20 10:15:50 1995 10 if ( dv->selected->loaded==NULL | | I 'dv->selected->loaded->noname tt 'dv->selected->loaded->new )) DeleteURLIbuffer) ,- /* I do this because Ghost pages aren't deleted from miniw ebs anymore */ PageRemove(dv->selected->loaded,NULL_WIN) , DocRemovePart(dv->doc,dv->selec ed, true) , DocRedraw(dv->doc) ; myfree(buffer) ; ) } void XVT_CALLC0NV1 DocCopy(WINDOW w) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , if I dv->selected==NULL 1 xvt_scr_beeρ() , else DocCopyURL(w) ; } void XVT_CALLC0NV1 DocCu (WINDOW w) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , if ( dv->selected==NULL ) xvt_scr_beep() ; elεe { DocCopy(w) , DocClear(w) , ) ) void XVT_CALLC0NV1 DocPaste(WINDOW w) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , int beep=l, char "str, "title, "url, long len, char space[200], "buf, int sizebuf, if ( xvt_cb_open(false) ) I beep = 0; if (I str=xvt_cb_get_data(CB_APPL, "LINK" ,tlen) ) '= NULD ( title = copylstr) , url = copy(str+strlen(tιtle)+1) , DocAddPageName(dv->doc, url, -1, -1), myfree(title) ; myfree(url) ; ) else if (( str=xvt_cb_get_data(CB_APPL, "XLNK" , tlen)) '= NULL) { title = copylstr) ; url = copy(str+strlen(title)+1) ; strcpy(space, fsys_nametaιl(url) ) ; buf = myalloc(εizebuf=strlen(dv->doc->name)+strlen(space)+30) , fsys_buιld_name(dv->doc->name,space,buf,εizebuf) ; CopyClιpToFιle(buf,dv->doc) , myfree(title) , myfree(url) ; myfree(bu ) , ) elεe { beep = 1; } xvt_cb_cloεe() ; ) if ( beep ) xvt_scr_beep( 1 , docadit .c Mon Mar 20 10 : 15 : 50 1995 11 static int ImportOk (voιd "ctx, char "url , struct chooserinfo "info ) { Document "doc = ( (DocView * ) ctx ) ->doc , DocAddPageName (doc , url , inf o->saveιmages , mfo->fullurl ) , return 1 ; ) void Docl port(WINDOW w) { DocView "dv = (DocView *)xvt_vob 3 _get_data(w) ; char "buffer; mt εizebuf,- buffer = myalloc(sιzebuf=1000) , buffer[O]='N0' ; Chooεel ( (View *)dv, Choose_Import/""Import page "*/, buffer, εizebuf, CHOOSER_IMPORT, ImportOk) , myfree(buffer) ; ) void XVT_CALLC0NV1 DocUnrefPage(Page "page) { DocPart "dp, char "pt, i f ( page->doc ' =NULL ) { pt = fsys_nametaιl (page->url) ; if ( εtrcmp(pt,dp->relurl)==0 ) { dp->loaded = NULL; break; } } ) page->doc = NULL, myfree(page->docname) ; page->docname = NULL; } void XVT_CALLC0NV1 DocSetPageToTemplate(Document "doc, Page "page) { Page "tpage, char "buffer, mt sizebuf, if ( doc->template'=NULL ) ( buffer = myalloc(sizebuf=strlen(doc->naune)+εtrlen(doc->template)+30) , fsys_buιld_name(doc->name,doc->template,buffer,sizebuf) ,- if (( tpage = PageSyncFind(buffer, " ",NULL,NULL) ) '=NULL ) PageCopyContents(page,tpage) ; myfree(buffer) , void XVT_CALLC0NV1 DocPageHeaderChanged(Document "doc. Page "page, t type) { DocPart "dp, *np, if ( doc==NULL ) return; dp = LookupDocPart(doc,page->url) ,- if ( dp==NULL ) return; if ( type==u_tιtle ) { if ( page->tιtle -= NULL it dp->tιtle NULL ) { } else if ( dp->tιtle==NULL ) { dp->tιtle = copy(page->tιtle) , docadit .c Mon Mar 20 10 : 15 : 50 1995 12 ) else if ( page->tιtle == NULL ) { myf ree ( dp- >tιtle ) , dp->tιtle=NULL, } else if ( strlen(page->tιtle)<=εtrlen(dp->tιtle) ) { strcpy(dp->tιtle,page->tιtle) , ) else { myfree(dp->tιtle) dp->tιtle = copy(page->tιtle) , } if I doc->docvιew'=NULL ) DocViewFillupFirst(doc->docvιew->w) , ) else if ( type==u_up ) { np = LookupDocPart(doc,page->upl) , if ( np'=dp->up tt dp->up'=NULL ) ( RemoveDown(doc,dp->up,dp) , DocRedraw(doc) , ) dp->up = np dp->upneedsdrawmg = true, if I np'=NULL ) np->downs = newDocPartLιnk(dp,np->downs, false, alse, false, false, false) , } else if ( type==u_style ) { np = LookupDocPart(doc,page->style) , if ( np 1 =dp->style tt dp->style'=NULL ) { RemoveBackLinkPage(doc,dp->style,dp) , DocRedra (doc) , } dp->style = np, dp->styleneedsdrawιng = true, if ( np'=NULL ) np->refered_by = newDocPartLink(dp,np->re ered_by, false, false, false, false, fals e); } ) void XVT_CALLCONVl PageCheckDocTitle(WINDOW w) { View "view = (View *) xvt_vob3_get_data(w) , Page "page = vιew->page, "pg, if I 'page->tιtlecomplaιned tt ( pg = PageLookupTιtle(page->tιtle,page) ) '=NULL ) ( navι_dm_post_warnιng(Docedιt_SameTιtle,pg->url) , page->tιtlecomplamed = true, ) if I page->docname==NULL ) return, if ( page->doc==NULL ) page->doc = DocSyncFmd(page->docname,view) if ( page->doc==NULL ) return, DocPageHeaderChanged(page->doc,pag ,u_tιtie) , ) void XVT_CALLCONVl DocChangeFirst(Document *doc, DocPart *dp) { DocPart 'pages, *prev, if ( doc->fιrst==dp ) return, prev = doc->fιrst, for ( pages = prev->another, pages'=NULL it pages'=dp, pages = pages->another ) prev = pageε, if ( pageε==NULL ) { IError("Not in document"), return, docedit . c Mon Mar 20 10 : 15 : 50 1995 13 ) prev->another = dp->another; dp->another = doc->fιrst; doc->first = dp; if(doc->last == dp) { for(dp=doc->flrεt;dp->another;dp=dp->another) ; doc->last = dp; } ) /*"****"/ static int SaveAsOklvoid *ctx, char *url, struct chooserinfo "unused) { DocView "dv = (DocView *) ctx; if( fsys_urlcmp(dv->doc->name,url)==0 ) ( DaveDocSave(dv->doc) ; dv->doc->saveasdone = true; return 1,- ) if (( XVT_OS_IS_WINOS tt dv->doc->nametype!=fn_doε tt !fsys_ιs_url (url) ) | | (XVT_0S == XVT_OS_MAC ti dv->doc->nametype>fn_mac tt ! fsys_ιε_url (url) ) ) { xvt_dm_post_error("Thiε miniweb may not be saved locally. It uses illegal filenam es" ) ; return 0; } dv->doc->saveasdone = true; if( url_exists(url) ) { navι_dm_post_error(Viewsave_AlreadyOpen, url) ; return 0,- } else { PublishDoc(dv->doc, url, false); ) return 1; ) int DaveDocSaveAs(Document *doc) ( char "buf; int ε zebuf=1000; if ( strlen(doc->name)>sιzebuf ) sizebuf = strlen(doc->name)+20; buf = myalloc(sizebuf) ; strcpy(buf, doc->name) ; doc->saveasdone = false; Chooselt( (View *)doc->docvιew,Viewcmd_Saveas, buf,sizebuf,CH0OSER_SAVEMW,SaveAsOk) ; return! doc->saveasdone ) ; } void XVT_CALLCONVl DocSaveAs(WINDOW w) { DocView "dv = (DocView *)xvt_vobj_get_data(w) ,- DaveDocSaveAs(dv->doc) ; ) void XVT_CALLC0NV1 DocSave(WINDOW w) ( Document "doc = ((DocView *)xvt_vob 3 _get_data(w) )->doc; if(doc->new) DaveDocSaveAs(doc) ; elεe DaveDocSave(doc) ; docadit.c Mon Mar 20 10:15:50 1995 14 } docσraph.c Mad Mar 22 09:14:52 1995 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved */ ♦include <xvt h> ♦include <math.h> ♦include <memory.h> ♦include "NaviPres h" ♦include "func.h" ♦include "doc.h" ♦include "xlocal h" ♦include "html.h" ♦include "icons.xbm" ♦include "icons.raw" ♦include <guess.h> extern char * guess_suffix(char *), ♦define MINWIDTH (32+32) ♦define MINHEIGHT (32+20) ♦define MINSEP (32+30) enum linktype { NormalLink, BothLink, UpBothLink, UpLink, InlmeLink FormLink StyleL k } , struct ad 3 acentcontext { DocPart "parent, DocPartLink "downs, }, COLOR linkcolours[StyleLιnk+1] { COLOR_BLACK, /* Normal */ COLOR_CYAN, /* Both */ COLOR_RED, /* UpBoth */ COLOR_RED, /* Up */ COLOR_BLUE, /* Inline */ C0L0R_GREEN, /* Form */ C0L0R_LTGRAY ) , /* Style */ COLOR localcolours [) = { COLOR_BLACK, /* Normal */ COLOR_GRAY, /* Ghost */ XVT_MAKE_COLOR{13,169,72) }, /* External */ static int FindLevelsl (DocView "dv, DocPart "page), static int FindLevelsInline(DocView "dv int *maxl), static int FindLevelsList(DocView "dv, int *maxl), static void FindLevels(DocView *dv) ; static void FιndAd 3 acentunattached(DocView "dv, int isextern) , static void FιndAd 3 acentSub(DocVιew "dv, DocPart "page ) , static void FmdAd 3 acentTop(DocView *dv) , static void FmdAd 3 acent(DocView *dv) , static int belongsto(DocPart "sub, DocPart "main), static void AssignTextLocation(DocView "dv DocPart "page, int as, int ds, int Id) static void DocPlacePage(DocPart "page,int x,mt y) , static int AssignLocationsTree(DocView "dv, DDooccPPaarrtt ""ppaaggee,, int y) , static mt AssignRadiiWeb(DocView "dv, int level), static void AssignLocationsWeblDocView "dv int level, mt center), static void AssignLocationsUnattached(DocView "dv, mt width, mt height), static void AssignLocations(DocView *dv) , static void RctIntersectWιthLιne(PNT "res, PNT *pl, PNT *p2, RCT *rct), static void DrawLine(DocView "dv, DocPart "from, DocPart "to, enum linktype type, DRAW_CTO OLS "ctool) , static void DrawLinkLine(DocView "dv, DocPart "dp, DocPartLink "dl, DRAW_CTOOLΞ "ctool), static void DocDrawLines(DocView "dv, RCT *rct) , static XVT_IMAGE Findlconlchar "contenttype, int ghost, int), static void DocDrawPage(DocView "dv, DocPart "page, DRAW_CTOOLS "ctool), static int FindLevelsl(DocView "dv, DocPart "page) { docgraph.c Wad Mar 22 09:14:52 1995 2 mt sublevel = page->level+l; DocPartLink *pl; int maxl = page->level, ml; Document "doc = dv->doc; if ( page==doc->first it doc->graph_type == g_web ) sublevel = page->level, for I pl=page->downs; pl'=NULL; pi = pl->next ) { if ( 'pl->page->levelassιgned ) { pl->page->level = sublevel, pl->page->levelassιgned = true; if ( ( ml = FindLevelsl(dv,pl->page) ) > maxl ) maxl = ml, ) } return( maxl ) , ) static int FindLevelsInline(DocView "dv, int " axl) ( DocPartLink *pl; int i, anychanged = false, DocPart "pages; Document "doc = dv->doc, for ( ι= "maxl; ι>=0; --ι ) { for ( pages= doc->fιrst, pages!=NULL; pages = pages->another ) { if I pages->levelassιgned tt pages->level==ι ) { for I pl=pages->refers_to, pl'=NULL; pl=ρl->next ) if ( ( pl->ιnlιned_ιmage | | pl->formlιnk ) tt !pl->page->levelassιgned ) { pl->page->levelassιgned = true; pl->page->level = i+l; lf I ι+l>*maxl ) "maxl = i+l; anychanged = true; } if ( pages->style'=NULL tt 'pages->style->levelasειgned ) pageε->εtyle->levelassιgned = true, pages->style->level = i+l; if ( ι+l>*maxl ) "maxl = i+l, anychanged = true; ) ) ) ) return! anychanged ); ) static int FindLevelsList(DocView "dv, t "maxl) { DocPartLink *pl; int l, anychanged = false, DocPart "pages, Document "doc = dv->doc; int ml; for ( ι=0; ι<= 'maxl; ++ι 1 { for ( pages= doc->fιrst; pages'=NULL; pages = pages->another ) ( if ( pages->levelassιgned it pages->level==ι ) { for ( pl=pages->refers_to; pl'=NULL; pl=pl->next ) if ( pl->from_lιst it 'pl->page->levelassιgned ) { pl->page->levelassιgned = true, pl->page->level = i+l, if ( ι+l>*maxl ) ' axl = i+l, if ((ml = FindLevelsl(dv,pl->page) )>*maxl) 'maxl = ml; docgraph.c Wad Mar 22 09:14:52 1995 3 anychanged = true; ) } } } return! anychanged ) ; ) static void FindLevels(DocView *dv) { DocPartLink *pl, DocPart 'pages; Document *doc = dv->doc; int mmlevel = doc->graph_type == g_web?0:i; int maxl, ml; int anychanged; for ( pages = doc->fιrst; pages!=NULL; pages = pages->another 1 if ( pages->external ) pages->levelaεειgned = true; else if I !pages->userplaced ) pages->levelaεsιgned = false; if ( doc->fιrst==NULL ) return; doc->fιrεt->level = 0; doc->fιrst->levelasειgned = true; if I doc->graph_type == g_web ) { maxl = 0; for ( pi = doc->fιrst->refers_to; pi'=NULL ; pi = pl->next ) { if I !pl->page->levelassιgned tt !pl->formlιnk it !pl->ιnlιned_ιmage tt !pl->page->up==NULL || ) ) { pl->page->level = 0; pl->page->levelassιgned = true; if (I ml=FιndLevelsl(dv.pl->page) )>maxl ) maxl = ml; ) ) if ( doc->fιrst->style'=NULL tt !doc->fιrst->style->levelassιgned ) { doc->fιrst->εtyle->level = 1; if ( l>maxl ) maxl=l; doc->fιrεt->style->levelasειgned = true; if (( ml=FιndLevelεl (dv,doc->fιrεt->style) )>maxl ) maxl = ml; } ) elεe maxl = FindLevelsl(dv,doc->first) ; anychanged = true; while ( anychanged ) { anychanged = false; anychanged = FindLevelsInline(dv,t axl) , if ( doc->graph_type '= g_web ) anychanged |= FindLevelsList(dv,tmaxl) ,- if ( anychanged ) { for ( pages= doc->firεt; pages!=NULL; pages = pages->another ) { if ( pages->up'=NULL it !pages->up->levelasειgned ) { pages->up->levelassιgned = true; pages->up->level = pages->level<=mιnlevel?mιnleve1:pages->level-1, if ((ml = FindLevelsl (dv,pages->up) )>maxl ) maxl = ml,- } ) } else { for ( pages= doc->fιrst; pages'=NULL; pages = pages->another ) ( docgraph.c Wad Mar 22 09:14:52 1995 if ( !pages->levelassigned it pages->refered_by!=NULL ) { for ( pl=pages->refered_by; pl'=NULL; pl=pl->next ) ( if ( pl->page->levelaεsιgned tt !pl->formlιnk it !pl->mlιned_ιmage) { pages->levelassιgned = true; pages->level = pl->page->level; if ( pages->level>maxl ) maxl = pages->level; if I I ml = FmdLevelεl (dv,pageε) )>maxl ) maxl = ml; anychanged = true; break; ) } lf I !anychanged ) for I pl=pages->refered_by; pl'=NULL; pl=pl->next ) { if ( pl->page->levelassιgned ) { pages->levelassιgned = true; pageε->level = pl->page->level, if ( pages->level>maxl ) maxl = pages->level, if (I ml = FindLevelsl(dv,pages) )>maxl ) maxl = ml; anychanged = true; break; } ) } /* Anything else is not reachable from the main page. These guys may /* form a web of their own, but for now we don't care */ /* Style sheets will fall nto this category "/ for ( pages = doc->fιrst; pageε'=NULL; pages = pages->another ) { if ( !pages->levelaεsιgned ) pageε->level = -1; ) if ( maxl>=dv->maxl ) { dv->levels = (DocPart **) myrealloc(dv->levels, (maxl+1) "sizeof(DocPart *)),- dv->levelnext = (DocPart **) myrealloc(dv->levelnext, (maxl+1)"sizeof(DocPart *)) dv->levelcnt = nt *) myrealloc(dv->levelcnt, (maxl+1)"sizeof( nt) ) ; dv->levelradιus = dnt *) myrealloc(dv->levelradιus, (maxl+1) "εizeofdnt) ) ; dv->maxl = ma l; ) dv->curl = maxl; int DocPageRefersTo(DocPart "pagel, DocPart *page2) { DocPartLink *pl; for ( pi = pagel->refers_to; pl!=NULL; pl=pl->next ) if ( pl->page == page2 ) return( true ) ; return! false ) , ) static void FindAdjacentunattached(DocView "dv, int isextern) { DocPart "prev, "trypage, "pages; DocPartLink *pl, "maybe; Document "doc = dv->doc; docgraph.c Wad Mar 22 09:14:52 1995 5 prev = NULL, for ( pages = doc->fιrst, pageε'=NULL, pages=pages->another ) { if ((isextern it pages->external it 'pages->userplaced) | | ('isextern it pages->level == -1 it 'pages->besιded )) { if ( prev==NULL ti isextern ) dv->externalε = pageε, else if ( prev==NULL ) dv->unattached = pages, else prev->besιde = pageε; pageε->besιded = true, trypage = pages,- while ( trypage' =NULL ) { prev = trypage; trypage = NULL; maybe = NULL; for ( pl=pages->refers_to; pl'=NULL ; pi = pl->next ) ( if (dεextern it pl->page->external tt 'pl->page->userplacedl | | ('isextern tt pl->page->level == -1 tt 'pl->page->besιded ) ) if ( pl->bothways ) break; maybe = pi, } } if ( pl==NULL ) pi = maybe; if ( pl'=NULL ) { trypage = pl->page, prev->besιde = trypage, trypage->beειded = true; } else trypage = NULL, } static void FιndAd 3 acentSub(DocView "dv, DocPart "page ) { DocPart "prev; DocPart "any = NULL, DocPartLink "dl, page->besιded = true; page->beside = dv->levels [page->level] , dv->levels [page->level]= page, if ( page->level<dv->curl ) { do ( prev = dv->levels [page->level+l] ; any = NULL; if ( prev'=NULL ) { for ( dl=page->downs; dl '=NULL it any==NULL, dl=dl->next ) if ( 'dl->page->besιded tt dl->page->level==page->level+l tt DocPageReferεTo(prev, dl->page) ) any = dl->page; for ( dl=page->referε_to; dl'=NULL ti any==NULL, dl=dl->next if ( dl->page->up==NULL it ' dl->page->besιded tt dl->page->level==page->level+1 it DocPageRefersTo (prev, dl->page) ) any = dl->page; } if ( any==NULL ) { for ( dl=page->downs; dl ' =NULL tt any==NULL; dl=dl->next ) if ( 'dl->page->besιded tt dl->page->level==page->level+l ) any = dl->page, docgraph.c Wad Mar 22 09:14:52 1995 6 for ( dl=page->refers_to; dl!=NULL ii any==NULL; dl=dl->next ) if ( dl->page->up==NULL it !dl->page->besιded it dl->page->level==page->level+l ) any = dl->page, } if ( any'=NULL ) FιndAd 3 acentSub(dv,any) ; } while ( any'=NULL ) , ) ) static void FιndAd 3 acentTop(DocView *dv) { DocPart "prev; DocPart "any = NULL; DocPart "pages; int l; if ( dv->doc->fιrst==NULL ) return; for ( ι=0; κ=dv->curl, ++ι ) { do { prev = dv->levels[l] , ; pages'=NULL it any==NULL, pages = pages->anoth er if ( 'pages->beειded tt pages->level==ι tt DocPageRefersTo(prev,pages) ) any = pages; it any==NULL, pages = pages->anoth er if ( ipages->besιded it pages->level==ι 1 any = pages; } if ( any'=NULL ) FιndAd 3 acentSub(dv,any) , } while I any'=NULL ) ,- ) static void FιndAd 3 acent(DocView *dv) { int l, cnt,- DocPart "pages; Document "doc = dv->doc; for ( ι=0; κ=dv->curl; ++ι ) dv->levels[ι)=NULL, dv->unattached = NULL; for ( pages = doc->fιrst; pages'=NULL; pages = pages->another ) ( pages->besιde = NULL; pages->besided = false; FιndAd 3 acentunattached(dv,true) , FmdAd 3 acentunattached(dv,false) ; FmdAd 3 acentTop(dv) , for ( ι=0; κ=dv->curl; ++ι ) { for ( cnt=0, pages=dv->levelε[1] ; pages'=NULL,- pages=pages->besιde ) ++cnt; docgraph.c Wad Mar 22 09:14:52 1995 7 dv->levelcnt[I] = cnt, } for ( cnt=0, pages=dv->unattached, pages'=NULL, pages=pageε->besιde ) ++cnt, dv->unattachedcnt = cnt, ) static int belongsto(DocPart "sub, DocPart "main) { if ( sub->up == mam ) return( true ) , return ( εub->up == NULL tt DocPageRefersTo(mam,sub) ) , } static void AsεignTextLocation(DocView "dv, DocPart "page, int aε, mt ds, int Id) ( char "pt, int width, pt = fsys_nametaιl2 (page->relurl) , width = xvt_dwιn_get_text_wιdth(dv->pane,pt, -1) , page->tbb left = (page->bb left+page->bb right-width) /2 page->tbb top = page->bb.bottom+ld, page->tbb right = page->tbb left+width, page->tbb bottom = page->tbb top+as+ds, page->needsplacιng = false, page->as = as, ) static void DocPlacePage(DocPart "page,int x,mt y) { page->bb.top = y, page->bb.left = x, page->bb.right = x+32, page->bb.bottom = y+32, ) static mt AssignLocationsTiee(DocView "dv, DocPart "page, mt y) ( int len=0, DocPart "subpage, if ( page==NULL ) /* Nothing in tree */ return(0 ) , if ( page->level<dv->curl ) for I subpage = dv->levelnext[page->level+l] , subpage'=NULL tt belongsto(subpage p age) ; subpage = subpage->besιde ) len += AssignLocationsTree(dv,εubpage,y+len) if ( len < MINHEIGHT ) len=MINHEIGHT; page->sublen = len; if ( 'page->userplaced ) { DocPlacePage(page, page->level*MINWIDTH+MINWIDTH/2, y+(len-MINHEIGHT)/2) , ) dv->levelnext[page->level]=page->besιde, return( len ) , ) static t AssιgnRadιιWeb(DocVιew *dv, int level) { int subradiuε, radiuε, if ( level>dv->curl ) return( 0 ) , subradius = AssignRadnWebtdv, level+1) , if(dv->levelcnt[level] ) docgraph.c Wad Mar 22 09:14:52 1995 8 radius = (int) (((double) dv->levelcn [level] *(MINSEP) )/6.28 + 51+2, else radius = MINWIDTH; if ( radιus<MINSEP 1 radius = MINWIDTH, if ( subradιus'=0 tt radιus<subradιus+2*MINHEIGHT+3 ) radius = subradius + 2ΗINHEIGHT+3; dv->levelradius[level] = radius; return( radius ) ; } static void AssιgnLocatιonsWeb(DocVιew *dv, int level, int center) ( double angle= -3.14, incr; double radius = dv->levelradιus[level] ; double desiredradius; mt l; DocPart 'subpage, 'up; DocPartLink *dl; if ( dv->levelcn [level]==0 ) return; if ( level '=0 ) { up = dv->levels[level] ->up; if ( up==NULL ) { for ( dl=dv->levels[level]->refered_by; dl'=NULL ii up==NULL, dl=dl->next ) if ( dl->page->level==level-l ) up = dl->page; } if ( up'=NULL ) angle = up->angle; ) incr = 6.28/dv->levelcn [level] ; desiredradius = (((double) dv->levelcnt[level]* (MINSEP+10) ) /6.28 + -5)+2, if ( desιredradιus<radιus ) incr *= desiredradius/radius • for ( ι=0, subpage = dv->levels[level] ; subpage'=NULL; subpage=subpage->besιde, ++ι ) { if ( !subpage->userplaced ) { DocPlacePage(subpage,center + (int) (radιus*cos(angle) ) center + dnt) (radius"sin(angle) )) ; } subpage->angle = angle, angle += incr; } static void AssignLocationsUnattache (DocView "dv, int width, mt height) { t w=0, h=0; DocPart "pages; int ok=true; for ( pages = dv->unattached; pages!=NULL tt ok; pages=pages->besιde ) if ( pages->bb.top<=heιght it pages->bb.left<=wιdth ) ok = false; for ( pages = dv->externals; pageε'=NULL it ok; pages=pages->besιde ) if ( pages->bb.top<=he ght tt pages->bb.left<=wιdth ) ok = false; if ( ok ) ( /* Nothing to be done */; ) else if ( width>heιght+100 ) { /* screens tend to be wider than high */ h = height; if ( dv->externals!=NULL ) { w = MINWIDTH/2; h += 2*MINHEIGHT; for ( pages=dv->externals; pagesi=NULL; pages = pages->besιde ) { docgraph.c Wad Mar 22 09:14:52 1995 if ( 'pages->userplaced ) { DocPlacePage(pages,w,h) , w += MINWIDTH; if ( w>wιdth ) width = w, } if ( dv->unattached'=NULL ) { w = MINWIDTH/2, h += MINHEIGHT, if ( dv->externals==NULL ) h+= MINHEIGHT, for ( pages=dv->unattached; pages'=NULL, pages = pages->besιde ) { f ( 'pages->userplaced ) { DocPlacePage(pages,w, h) ; w += MINWIDTH, } } if ( w>wιdth ) width = w, } height = h+MINHEIGHT, ) else { w = width, if ( dv->externals'=NULL ) { w += 2*MINWIDTH; h = 0; for ( pages=dv->externals; pages '=NULL, pages = pages->besιde ) { if ( 'pages->uεerplaced ) { DocPlacePage!pages,w,h) , h += MINHEIGHT; } ) if ( h>heιght ) height = h; } if I dv->unattached '= NULL ) { w += MINWIDTH; h = 0; if ( dv->externals==NULL ) w += MINWIDTH; for ( pages=dv->unattached, pages '=NULL, pages = pages->besιde ) { if ( 'pages->userplaced ) { DocPlacePage(pages, ,h) , h += MINHEIGHT, ) } if h>heιght ) height = h; } width = w+MINWIDTH; for ( pages=dv->doc->fιrst; pages '=NULL; ρages=pages->another ) if ( wιdth<pageε->tbb.right ) width = pages->tbb.right; if ( heιght<pages->tbb.bottom ) height = pages->tbb.bottom, ) dv->totwιdth = w dth+MINWIDTH; dv->totheιght = height+MINHEIGHT; ) static void AssignLocations (DocView *dv) { int height, width, I, radius, h, hi. Document *doc = dv->doc; DocPart 'page; int as, ds. Id; if ( doc->graph_type==g_tree ) { for ( 1=0; κ=dv->curl , ++ι ) dv->levelnext[ι] = dv->levels [l] , docgraph.c Wad Mar 22 09:14:52 1995 10 h = height = AssignLocatιonsTree(dv,doc->first,0) ,- width = (dv->curl+l)"MINWIDTH; for ( ι=0; κ=dv->curl ; ++ι ) { hi = h; for ( page = dv->levelnext[i] ; page'=NULL, page=page->besιde, hι+=MINHEIGHT ) DocPlacePage(page,ι*MINWIDTH+MINWIDTH/2,hι ) ; if ( hι>heιght ) height = hi; ) ) elεe ( radius = AssignRadnWebfdv,0) ; for ( 1=0; κ=dv->curl; ++ι ) AssιgnLocatιonsWeb(dv,i,radius+MINWIDTH) ,- height = 0; if ( dv->doc->fιrst'=NULL ) height = dv->doc->fιrεt->bb.top; for ( ι=0; κ=dv->curl ; ++ι ) for ( page=dv->levels[l] ; page'=NULL; page=page->besιde ) if ( page->bb.top<he ght ) height = page->bb.top, if ( heιght>MINHEIGHT ) ( height -= MINHEIGHT, for ( 1=0; κ=dv->curl ; ++ι ) for ( page=dv->levels ] ; page'=NULL, page=page->besιde ) { if ( !page->uεerplaced ) { page->bb.top-=heιght; page->bb.bottom-=heιght,- } ) } height = width = 0; for ( ι=0; κ=dv->curl ; ++ι ) for ( page=dv->levels(ι] ; page'=NULL; page=page->besιde ) { if ( page->bb.bottom>heιght ) height = page->bb.bottom, if ( page->bb.πght>wιdth ) width = page->bb.right, ) } AsεignLocationsUnattachedIdv,width,height) , xvt_dwιn_get_font_metrιcε(dv->pane,ild.tas.tds) ; for ( page=dv->doc->first; page'=NULL; page=page->another ) { AsεignTextLocation(dv,page,aε,dε, Id) ; ) } void XVT_CALLCONVl DocRegraphfDocView "dv, enum graph_type gt) { Document "doc = dv->doc; doc->graph_type = gt; FindLevels(dv) ; FιndAd 3 acent(dv) ; AssignLocations(dv) ; DocScrollSync(dv) ; } static void RctlntersectWithL efPNT "res, PNT *pl, PNT *p2, RCT *rct) ( /* Assumption pi is at center of ret, ret is close to square */ t x,y,- if ( pl->h>p2->h ) ( if ( pl->v>p2->v ) { if ( pl->h-p2->h > pl->v-p2->v ) { x = rct->left; y = pl->v + ( ( (x-pl->h) * (pl->v-p2->v) )/(pl->h-p2->h) ) , } else { docgraph.c Wad Mar 22 09 : 14 : 52 1995 11 y = rct->top; x = pl->h + (((y-pl->v) * (pl->h-p2->h) ) / (pl->v-p2->v) ) ; } } else if ( pl->v==p2->v ) { y = pl->v; x = rct->left; } else { if ( pl->h-p2->h > p2->v-pl->v ) ( x = rct->left; y = pl->v + ({(x-pl->h) * (pl->v-p2->v) )/ (pl->h-p2->h) ) , } else { y = rct->bottom+15; /* Space for text */ x = pl->h + ( ( (y-pl->v) * (pl->h-p2->h) )/ (pl->v-p2->v) ) , ) } } else if ( pl->h==p2->h ) { x = pl->h; y = pl->v>p2->v'rct->top:rct->bottom, } else ( if ( pl->v>p2->v ) ( if ( p2->h-pl->h > pl->v-p2->v ) { x = rct->rιght, y = pl->v + ( ( (x-pl->h) • (pl->v-p2->v) )/ (pl->h-p2->h) ) ; } else { y = rct->top; x = pl->h + ( ( (y-pl->v) * (pl->h-p2->h) )/ (pl->v-p2->v) ) ; } } else if ( pl->v==p2->v ) { y = pl->v; x = rct->rιght, ) else { if ( p2->h-pl->h > p2->v-pl->v ) ( x = rct->rιght, y = pl->v + ( ( (x-pl->h) * (pl->v-p2->v) 1 / (pl->h-p2->h) ) . } else { y = rct->bottom; x = pl->h + ( ( (y-pl->v) * (pl->h-p2->h) )/ (pl->v-p2->v) ) , } ) } res->h = x, res->v = y; ) static void LinelntersectWithLmetPNT 'res, PNT *pl, PNT *p2, DocPart 'thing) { /* Yes I do mean to use top in one place and bottom in another, I need to */ /* use top to check for intersection. I should really recalculate h, but */ /* seems harder than it's worth */ int h; if ( p2->v>thmg->tbb.bottom ) { h = pl->h+ ( (p2->h-pl->h) * (thιng->tbb.top-pl->v) )/ (p2->v-pl->v) , if ( h>=thιng->tbb.left it h<=thιng->tbb.right ) { res->h = h; res->v = thιng->tbb.bottom; ) ) ) static void DrawLine(DocView "dv, DocPart "from, DocPart "to, enum linktype type, DRAW_CTO OLS 'ctool) { PNT pi, p2, oldpl, oldp2; mt mod; docgraph.c Wad Mar 22 09 : 14 : 52 1995 12 i f ( from==to ) return; pl.h = (from->bb.left+from->bb.right) /2; pl.v = (from->bb.top+from->bb.bottom) /2,- p2.h = (to->bb.left+to->bb.right) /2; p2.v = (to->bb.top+to->bb.bottom) 12,- oldpl = pi; oldp2 = p2; RctlntersectWithLine(ipl,ioldpl,toldp2,ifrom->bb) ; LinelntersectWithLine(tpl,toldpl,ioldρ2,from) ; RctlntersectWithLine(ip2.toldp ,ioldpl,ito->bb) ; LinelntersectWithLine(ip2,toldp2,ioldpl,to) ,- pl.h /= dv->reductιon; pl.v /= dv->reductιon; p2.h /= dv->reductιon; p2.v /= dv->reduction; pl.h -= dv->offleft; pl.v -= dv->offtop; p2.h -= dv->offlef ; p2.v -= dv->offtop; xvt_dwm_draw_set_poε (dv->pane , pl ) ; mod = false ; if ( !bw_dιsplay tt linkcolours[type] '=ctool->pen.color ) { ctool->pen.color = linkcolours[type] ; mod = true; > if I type==StyleLmk tt ctool->pen.style'=P_D0T ) { ctool->pen.style = P_D0T; mod = true; } else if ( type 1 =StyleLmk tt ctool->pen.style==P_DOT ) { ctool->pen.style = P_SOLID; mod = true; ) if ( mod 1 xvt_dwιn_set_cpen (dv->pane , tctool->pen ) ,- if I pl . h ! =p2 . h | | pl . v i =p2 . v ) xvt_dwιn_draw_alme (dv->pane , p2 , type==BothLιnk | | type==UpBothLιnk , true ) ; ) static void DrawLinkLine (DocView "dv, DocPart "dp , DocPartLink "dl , DRAW_CTOOLS "ctool ) { DrawLine (dv , dp, dl ->page , dl->upboth?UpBothLmk : dl->bothways?BothLιnk : dl->inlined_image? InlineLmk : dl-> formlιnk?FormLιnk : Nor alLink , ctool ) ; dl ->needsdrawιng = false ,- } static void DocDrawLines(DocView "dv, RCT "rctl { DocPart "page; DocPartLink *pl; DRAW_CTOOLS Ctools, • Document "doc = dv->doc; /* Draw any line which might intersect the rectangle */ xvt_dwin_get_draw_ctools(dv->pane,tctoolε) ; for ( page = doc->firεt; page!=NULL; page=page->another ) { if ( page->hιdden ) continue; if ( page->up!=NULL it !page->up->hidden it ! (page->bb.rιght<rct->left tt page->up->bb.rιght<rct->left ) tt ! (page->bb.left>rct->πght it page->up->bb.left>rct->rιght ) it ! (page->bb.bottom<rct->top tt page->up->bb.bottom<rct->top ) ti ! (page->bb.top>rct->bottom tt page->up->bb.top>rct->bottom )) ( DrawLine(dv,page,page->up,page->upboth?UpBothLink:UpLιnk,tctoolε) ,- page->upneedsdrawmg = false; ) if ( page->style!=NULL it !page->style->hιdden tt ! (page->bb.right<rct->left tt page->style->bb.rιght<rct->left ) tt ! (page->bb.lef >rct->rιght ti page->style->bb.left>rct->rιght ) tt ' (page->bb.bottom<rct->top tt page->style->bb.bottom<rct->top ) it docgraph.c Wad Mar 22 09:14:52 1995 13 ' (page->bb top>rct->bottom tt page->εtyle->bb top>rct->bottom )) ( DrawLine(dv,page,page->style,StyleLink,tctools) , page->styleneedsdrawmg = false, } for ( pi = page->refers_to; pl'=NULL, pl=pl->next ) { if ( page->up'=pl->page ti pl->page->up'=page ii 'pl->page->hιdden tt ' (page->bb rιght<rct->left ii pl->page->bb rιght<rct->left ) tt ' (page->bb.left>rct->rιght it pl->page->bb left>rct->rιght ) ii ' (page->bb.bottom<rct->top tt pl->page->bb bottom<rct->top ) ii ' (page->bb top>rct->bottom it pl->page->bb top>rct->bottom ) ) { DrawLinkLine(dv,page,pi.tctools) , } ) } if ( 'bw_dιsplay tt COLOR_BLACK'=ctools pen color ) { ctools.pen color = C0L0R_kl_ACK, xvt_dwιn_set_cpen(dv->pane,tctools pen) , } ) static struct exttype { char "type, char "cmd, ) ιcontab[] = { (char *)0, (char *)0), static int freeable=0, static struct exttype "iconpt = icontab, static XVT_IMAGE *ιcon_ιmages, static int imgmax, struct exttype *XVT_CALLCONVl ιcon_mappιngs(void) { return! iconpt ) , } void XVT_CALLC0NV1 set_ιcon_mappmgs(εtruct exttype "newmap) ( t i, char "type, if ( freeable ) { for ( ι=0, iconptd] type'=NULL, ++ι ) { myfree(iconpt[l] type) myfree(iconpt[I] cmd), if ( ιcon_ιmageε[ι] '=NULL ) xvt_ιmage_destroy(ιcon_ιmages[I] 1 , ) myfree(iconpt) , } iconpt = newmap, for ( ι=0, iconpt[l] .type 1 =NULL, ++ι ) if ( ι>imgmax ) ιcon_ιmages = (XVT_IMAGE *) myrealloc(ιcon_ιmageε, (ιmgmax=ι1 "sizeof(XVT_IMAGE) for ( ι=0, ιconpt(ι) type'=NULL; ++ι ) { type = guess_suffix(iconp [i] cmd), if ( pmatch(type, "image/gif") ) ιcon_ιmages[i] = xvt_ιmage_read_gιf(iconpt[I] cmd), else if ( pmatch(type, "image/ 3 peg" ) ) ιcon_ιmages[1] = xvt_ιmage_read_ 3 peg(iconpt[I] cmd) else ιcon_ιmages[i] = xvt_ιmage_read(iconpt ) cmd) ) freeable = 1, docgraph.c Wad Mar 22 09:14:52 1995 14 static εtruct { char "content; XVT_IMAGE image; } εtd_ιcons[] = { "text/html" }, "ghost/text/html" ), "image" ) , "ghost/image" } , "application/x-navistyle" }, "ghost/application/x-navistyle" } , "audio" } , "ghost/audio" }, "video" }, "ghost/video" ) , "application/x-navimap" ) , "ghost/application/x-navimap" ), "ghoεt" ), ♦define Unknownlcon 13 { "" ), NULL) ; static XVT_IMAGE noname_page; εtatic XVT_IMAGE mod_page; char * XVT_CALLC0NV1 WeblconBi s(int *w int *h ) ( *w = web_wιdth; *h = web_heιght; return! web_bιts ),- ) char * XVT_CALLC0NV1 MWeblconBits (mt *w, mt *h ) { *w = mweb_wιdth; *h = mweb_heιght; return! mweb_bιts 1; } XVT_IMAGE XVT_CALLC0NV1 Pagel age(int type ) { if ( type==0 ) return! std_ιcons [0] .image ),- else if ( type==l ) return( mod_page ) ; else returnI noname_page ) ; } void XVT_CALLC0NV1 Initlcons (void) { std_ιcons[0] .image = LoadRawIcon(web_bmp,web_wιdth,web_he ght1 ,- if ( !bw_dιsplay ) std_ιcons[1] .image = LoadRawIcon(gweb_bmp,web_wιdth,web_heιght) ; else std_ cons[1] .image = Loadlcon(gweb_bιts,gweb_wιdth,gweb_heιght) ,- noname_page = LoadRawIcon(nweb_bmp,nweb_wιdth,nweb_heιght) ; mod_page = LoadRawIcon(mweb_bmp,mweb_width,mweb_heιght) ; std_ιcons[2] .image = LoadRawIcon(ιmage_bmp,ιmage_wιdth,ιmage_heιght) ; if ( !bw_display ) std_ιcons[3] .image = LoadRawIcon(gιmage_bmp,gιmage_width,gιmage_heιght) , else std_icons[3) .image = Loadlcon(gιmage_bιts,gιmage_wιdth,gιmage_heιght) ; std_ιcons[4] .image = LoadRawIcon(style_bmp,style_wιdth,εtyle_heιght) ; if ( !bw_dιsplay ) std_ιcons[5) .image = LoadRawIcon(gstyle_bmp,gstyle_wιdth,gstyle_heιght) else std_ιcons(5] .image = LoadIcon(gstyle_bιts,gstyle_wιdth,gstyle_heιght) ,- std_ιcons[6] .image = LoadRawIcon(snd_bmp,snd_wιdth,snd_heιght) ; if ( !bw_display ) std_ιcons[7] .image = LoadRawIcon(gsnd_bmp,gsnd_wιdth,gsnd_heιght) ; else std_ιcons[7] .image = LoadIcon(gsnd_bιts,gsnd_wιdth,gsnd_heιght) ; std_ιcons[8] .image = LoadRawIcon(vιdeo_bmp,vιdeo_wιdth,vιdeo_heιght) ; if ( !bw_dιsplay ) docgraph.c Wad Mar 22 09:14:52 1995 15 std_ιcons[9] .image = LoadRawIcon(gvιdeo_bmp,gvιdeo_wιdth,gvιdeo_heιght) , else std_ιcons[9] .image = LoadIcon(gvιdeo_bιtε,gvιdeo_wιdth,gvιdeo_heιght) , std_ιcons [10] .image = LoadRawIcon(map_bmp,map_wιdth,map_heιght) , if ( 'bw_dιsplay ) std_ιcons[11] .image = LoadRawIcon(gmap_bmp,gmap_wιdth,gmap_heιght) , elεe std_ιcons[11] .image = Loadlcon(gmap_bιts,gmap_wιdth,gmap_heιght) , std_ιcons[13] .image = LoadRawIcon(random_bmp,random_wιdth,random_heιght) , if I 'bw_dιsplay ) std_ιcons[12] .image = LoadRawIcon(grandom_bmp,grandom_wιdth,grandom_heιght) , else std_ιcons[12] .image = LoadIcon(grandom_bιts,grandom_w dth,grandom_heιght) , } εtatic XVT_IMAGE Findlconlchar "contenttype, int ghost, int mod) { char buffer[200] , int l , if ( ghost ) { sprintf! buffer, "ghost/%s", contenttype ), contenttype = buffer, ) for ( ι=0, iconpt[ι] .type'=NULL, ++ι ) { if ( pmatch!iconpt[l] type,contenttype) tt ιcon_ιmages[l] '=NULL ) ( return! ιcon_ιmageε[i] ) ; ) ) for I ι=0; εtd_ιcons[ι] content'=NULL, ++ι ) ( if ( pmatch!std_ιcons [I] .content,contenttype) ) { f ( ι==0 ti mod==l 1 return! mod_page ) , if ( ι==0 ii mod==2 1 return( noname_page ) ; returnI εtd_ιconε[i] .image ), } ) return! std_ιcons[Unknownlcon-ghost] .image ), ) static void DocDrawPage(DocView "dv, DocPart "page, DRAW_CTOOLS "ctool) { RCT irect, drect, XVT_IMAGE image, char "pt, mt lc, f ( page->hιdden ) return; if ( dv->reductιon==l ) { image = FιndIcon(page->contenttype, 'page->exιsts, (page->loaded'=NULL it (page->loaded->noname || page->loaded->new) ) '2 page->loaded'=NULL tt (page->loaded->changed| |page->loaded->temporarychang ed)?l:0) ; irect.left = 0; irect.top = 0, xvt_ιmage_get_dιmensιonε(image,tirect.right,tirect.bottom) , drect.left = page->bb.left-dv->offieft, drect. op = page->bb.top-dv->off op, drect.right = drect.left+irec .right, drect.bottom = drect.top+irect.bottom, if ( drect.lef <dv->wιdth-6 ti drect.lef +irec .rιght>=7 ) /* Wierd xvt bug * / xvt_dwιn_draw_ιmage(dv->pane, image,tdrect,tirect) ,- pt = fsys_nametaιl2 (page->relurl) , lc = page->external ' 2 : page->exιsts ' 0 1, if ( 'bw_dιsplay tt localcolours[lc] '=ctool->fore_color ) { ctool->fore_color = localcolours[lc] , docgraph.c Wad Mar 22 09:14:52 1995 16 xvt_dwιn_set_draw_ctoolε (dv->pane,ctool) ; ) xvt_dwιn_draw_tex (dv->pane,page->tbb.left-dv->offief ,page->tbb.top-dv->off op+pa ge->as, pt,-l); } else { drect.left = page->bb.left/dv->reductιon-dv->offieft,- drect.top = page->bb top/dv- >reductιon-dv->offtop, drect.right = drect.left+32/dv->reductιon; drect.bottom = drect. op+32/dv->reductι on; xvt_dwm_draw_rect(dv->pane,tdrect) ,- } page->needsdrawιng = false,- } void XVT_CALLC0NV1 DocDraw(DocView "dv, RCT *rct) ( DocPart "page; Document "doc = dv->doc; DRAW_CTOOLS old, new; if ( dv->reductιon<l ) dv->reductιon=l; if ( dv->reductιon>16 ) dv->reductιon=16; xvt_dwιn_set_clιp(dv->pane,ret) ,- xvt_dwιn_clear(dv->pane, bg_col) ; rct->left ♦= dv->offief ; rct->rιght += dv->offleft; rct->top += dv->offtop; rct->bottom += dv->offtop; rct->left *= dv->reduct on; rct->rιght *= dv->reductιon; rct->top *= dv->reductιon; rct->bottom *= dv->reductιon; DocDrawLines( v,ret) ; xvt_dwm_get_draw_ctools(dv->pane,told) ; new = old; new.opaque_text = true; xvt_dwm_set_draw_ctools(dv->pane.tnew) , for ( page = doc->fιrst; page'=NULL; page = page->another ) { if ( xvt_rect_ιntersec (NULL,ret,ipage->bb) | | xvt_rect_ιntersec (NULL,rct,tpage->tbb) ) DocDrawPage(dv,page,tnew) ; } xvt_dwιn_set_draw_ctools(dv->pane,told) ; if ( dv->εelected '= NULL tt 'dv->εelected->hιdden) /* It lε safe to do this*/ HighlightDocPart(dv,dv->selected) ,- /* if we are clipped */ xvt_dwm_εet_clιp(dv->pane,NULL) ; } void XVT_CALLC0NV1 DocRedrawDP(Document "doc, DocPart "dp) { DRAW_CTOOLS old, new; DocView "dv = doc->docvιew; if ( dv==NULL 1 return,- xvt_dwm_get_draw_ctoolε(dv->pane,told) ; new = old; new.opaque_text = true; xvt_dwιn_set_draw_ctools(dv->pane,tnew) ,- DocDrawPage(dv,dp,tnew) ; xvt_dwιn_εet_draw_ctoolε(dv->pane,told) ,- ) void XVT_CALLCONVl DocRedraw(Document *doc) DocView "dv = doc->docvιew; RCT ret, if ( dv==NULL ) docgraph.c Wad Mar 22 09:14:52 1995 17 return; DocRegraph(dv,doc->graph_type) ; xvt_vob 3 _get_clιent_rect(dv->pane,irct) , xvt_dwιn_ιnvalιdate_rect(dv->pane,irc 1 , ) void XVT_CALLCONVl DocUpdatePane(Document *doc) ( DocView "dv = doc->docvιew; RCT ret, if ( dv==NULL 1 return; xvt_vob 3 _get_clιent_rect(dv->pane,tret) ; xvt_dwm_ιnvalιdate_rect(dv->pane,tret) , } void XVT_CALLCONVl DocViewDoUserPlaced(Document "docl ( DocPart 'pages; int aε.dε.ld, if ( doc->docvιew==NULL ) return; xvt_dwιn_get_font_metrιcs(doc->docvιew->pane,tld,tas,ids) ; for ( pages = doc->fιrst; pages!=NULL; pageε = pages->another ) ( if ( pages->userplaced ) { DocPlacePage(pages, ageε->bb.left,pageε->bb.top) , AssιgnTextLocatιon(doc->docvιew,pages,as,ds, Id) , } ) DocRedraw(doc) , ) void XVT_CALLC0NV1 DocRese (Document *doc) { DocPart "pages; for ( pages = doc->fιrst; pages'=NULL; pageε = pages->another 1 pages->userplaced = false, DocRedraw(doc) , ) void XVT_CALLCONVl DVInsertU(DocView "dv, DocPart "dp, DocPart "at) { DocPart *pg, 'prev; if ( *at==NULL ) { 'at = dp; if ( dv->totheιght>dv->totwιdth ) { DocPlacePage(dp,dv->totwιdth,MINHEIGHT/2) , } else { DocPlacePage(dp,MINWIDTH/2,dv->totheιght) , } } else { prev= 'at; for ( pg=prev->besιde; pg'=NULL, pg=prev->besιde 1 prev = pg; prev->besιde = dp; if ( dv->externals'=NULL tt ('at) ->bb.left>dv->externals->bb.top ) { DocPlacePage(dp,prev->bb.left,prev->bb.top+MINHEIGHT) , ) else { DocPlacePage(dp,prev->bb left+MINWIDTH,prev->bb.top) ; ) ) } docgraph.c Wad Mar 22 09:14:52 1995 18 void XVT_CALLCONVl DocPosition(Document *doc, DocPart *dp) { DocView *dv = doc->docview; DocPart *pg, 'prev, 'maybe; DocPartLink *pl; int as,ds,ld; if ( dv==NULL ) return; dp->level = -1; if ( dp->external ) { DVInsertU(dv,dp,idv->externals) ; } else if ( dp->refered_by==NULL it dp->downs==NULL ) { DVInsertU(dv,dp,tdv->unattached) ; ) else if ( doc->graph_type==g_tree ) { if ( dp->up!=NULL tt dp->up->levelassιgned ) dp->level = dp->up->level+l; else { maybe = NULL; for ( pl=dp->refered_by; pl!=NULL tt !pl->from_lιst; pl=pl->next if ( pl- page->levelassιgned ) maybe = pl->page; lf { pl==NULL ii maybe==NULL ) DVInsertU(dv,dp,idv->unattached) ; else { if ( pl!=NULL ) dp->level = pl->page->level+l; else dp->level = maybe->level; if ( dp->level == 0 ) dp->level = 1; if ( dp->level>dv->curl ) dp->level = dv->curl; dp->levelassigned = true; prev= dv->levels[dp->level] ,- prev = pg; prev->besιde = dp; DocPlacePage(dp,prev->bb.lef ,prev->bb.top+MINHEIGHT) , ) } ) else { DocRedraw(doc) ; ) if ( dv->totheight<=dp->bb.top | | dv->totwιdth <= dp->bb.left ) ( if ( dv->totheight<=dp->bb.top ) dv->totheιght = dp->bb.top + MINHEIGHT; if ( dv->totwιdth <= dp->bb.left ) dv->totwidth = dp->bb.left + MINWIDTH; DocScrollSync(dv) ; ) xvt_dwin__get_font__metrics(dv->pane,tld,ias,ids) ; AsεignTextLocation(dv,dp,aε,ds,Id) ; } void XVT_CALLC0NV1 DocGraphNew(Document *doc) { DocPart 'dp; if ( doc->docvιew==NULL ) return,- for ( dp = doc->fιrst; dp'=NULL; dp = dp->another ) { if ( dp->needsplacmg 1 docgraph.c Wad Mar 22 09:14:52 1995 19 DocPosιtιon(docdp) ,- ) ) void XVT_CALLCONVl DocDrawNewlDocument *doc) { DRAW_CT00LS old, new; DocView *dv = doc->docvιew; DocPartLink *pl; DocPart 'dp; if ( dv==NULL ) return,- xvt_dwm_get_draw_ctools(dv->pane,told) ; new = old; new.opaςιue_text = true; xvt_dwιn_set_draw_ctools(dv->pane,tnew) ; for ( dp = doc->first; dp'=NULL; dp = dp->another ) ( if ( dp->up'=NULL tt dp->upneedsdrawιng ) ( DrawLine(dv,dp,dp->up,UpLιnk,tnew) ; dp->upneedsdrawing = false; } if ( dp->style'=NULL it dp->styleneedsdrawιng ) { DrawLine(dv,dp,dp->style,StyleLink.tnew) ; dp->styleneedsdrawιng = false; ) for ( pi = dp->refers_to; pl'=NULL; pl=pl->next ) { if ( dp->up'=pl->page it pl->page->up'=dp ϋ pl->needsdrawιng ) DrawLinkLine(dv,dp,pi,tnew) ,- ) } for ( dp = doc->fιrst; dp'=NULL; dp = dp->another ) { if ( dp->needsdrawιng ) ( DocDrawPage(dv,dp,tnew) ; if ( dp==dv->selected ) HighlightDocPart (dv, dp) ; } } xvt_dwm_set_draw_ctools (dv->pane , told) , docrafar.c Sat Mar 18 17:32:24 1995 /* Copyright 1994-1995 NaviSoft, Inc All rightε reεerved ♦include <xvt.h> ♦include "NaviPres.h" ♦include "func.h' ♦include "html.h" ♦include "view.h' ♦include "doc.h" ♦include <xlocal.h> ♦include "chooser h' Refers To Dialogue void XVT_CALLCONVl RefToUp(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , if ( dv->selected'=NULL it dv->selected->up'=NULL ) DocSetShowSelectιon(dv,dv->selected->up) , ) void XVT_CALLC0NV1 RefToLinkOut(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , DocPartLink *dl, mt sel, if ( dv->selected'=NULL ) { sel = xvt_lιst_get_sel_ιndex(xvt_wm_get_ctl (w,Re ersTo_Lιnks) ) , for I dl = dv->selected->refers_to, dl'=NULL it sel>0 , dl=dl->next, --sel) if ( dl'=NULL 1 DocSetShowSelection(dv,dl->page) , } } void XVT_CALLCONVl RefToFillup(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , WINDOW links = xvt_wιn_get_ctl(w,RefersTo_Lιnks) , DocPartLink *dl, int l, char buf[40] , xvt_lιst_suspend(links) , xvt_lιst_clear(links) , if I dv->selected==NULL ) { xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl(w, RefersTo_RelUrl),""), xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl (w, RefersTo_Up) , xvt_res_get_str(Docrefer_Up,buf,sizeo (buf))/*"Up"*/), xvt_vob 3 _set_enabled(xvt_wιn_get_ctl(w, RefersTo_Up) , false) , } else { xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl(w, RefersTo_RelUrl) , dv->selected->tιtle'dv->selected->tιtle:dv->selected->relurl) , xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl(w, RefersTo_Up) , dv->selected->up==NULL' xvt_res_get_str(Docrefer_Up,buf,sizeof(buf) ) /'"Up"*/: dv->selected->up->relurl) ; xvt_vob 3 _set_enabled(xvt_wιn_get_ctl(w, RefersTo_Up) ,dv->εelected->up'=NULL) for ( dl = dv->selected->refers_to, ι=0, dl'=NULL, dl = dl->next ) xvt_lιst_add(links, ι++,dl->page->tιtle?dl->page->tι le.dl->page->relurl) , ) xvt_lιst_resume(links) , } void XVT_CALLCONVl RefToSize(WINDOW w) ( RCT newsize, subsize, cu; WINDOW links = xvt_wm_get_ctl(w,RefersTo_Lmks) , WINDOW ups = xvt_wιn_get_ctl (w,RefersTo_Up) , WINDOW text = xvt_wιn__get_ctl(w, efersTo_RelUrl) , docrefar.c Sat Mar IB 17:32:24 1995 2 WINDOW dismiss = xvt_wιn_get_ctl (w, RefersTo_Dιsmιss) ; WINDOW copyurl = xvt_wιn_get_ctl (w, RefersTo_CopyUrl) , mt vdiff, hdiff; xvt_vob 3 _get_clιent_rect (w,tnewsize) ,- xvt_vob 3 _get_outer_rect (copyurl, icu) , xvt_vob 3 _get_outer_rect (links,tsubsize) , vdiff = newsize.bottom- (subsιze.bottom+9) , hdiff = newsize.right- (cu.rιght+10) , subsize.bottom += vdiff; subslze.right += hdiff; if ( subsize.bottom<subsιze. top+20 | | subsize.rιght<subsιze left+60 xvt_vob 3 _get_outer_rect (w, tnewsize) , if ( subsize rιght<subsιze. left+60 ) newsize.right += subsize.left+60 - subsize.right , if ( subsize.bottom<subsιze top+20 ) newsize.bottom += subεize. op+20 - subsize.bottom, xvt_vob 3 _move(w, tnewsize) , } else { xvt_vob 3 _move(links,tsubsize) , xvt_vob 3 _get_outer_rect (ups,tsubsize) , subsize.right += hdiff, subsize. left += hdiff, xvt_vobj_move(ups,tsubsize) ; xvt_vob 3 _get_outer_rect (dismiss,tsubsize) , subsize.right += hdiff; subsize. left += hdiff, xvt_vob 3 _move(dismiss,tsubsize) ,- cu. right += hdiff; cu.left += hdiff, xvt_vob 3 _move(copyurl,tcu) , xvt_vob 3 _get_outer_rect (text, tsubsize) , subsize right += hdiff, xvt_vob]_move ( ex ,tεubεize) ; } } void XVT_CALLCONVl DocShowReferεTo(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data (w) , if ( dv->refers_to '= NULL_WIN ) navι_vob 3 _raιse(dv->refers_to) ; elεe if (( dv->referε_to = xvt_wιn_create_res (RefersTo, TASK_WIN, EM_ALL, RefersTo_eh, (long) dv) ) ==NULL_WIN ) xvt_dm_post_error( "Can' t open window"), } void XVT_CALLC0NV1 DocDestroyRefTo(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) ; dv->refers_to = NULL_WIN; xvt_vob 3 _destroy(w) ,- Referenced By Dialogue void XVT_CALLC0NV1 RefByRefBy(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , DocPartLink *dl; mt Sel, if ( dv->selected'=NULL ) { sel = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl (w,RefBy_RefBy) ) , for I dl = dv->selected->refered_by, dl ' =NULL it sel>0 ; dl=dl->next, --sel) docrefar.c Sat Mar 18 17:32:24 1995 3 if ( dl'=NULL ) DocSetShowSelectιon(dv,dl->page) , ) ) void XVT_CALLCONVl RefByDowns(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , DocPartLink *dl, mt sel, if ( dv->selected'=NULL ) { sel = xvt_lιst_get_sel_ιndex(xvt_wm_get_ctl(w,RefBy_Downs) ) , for ( dl = dv->selected->downs, dl'=NULL it sel>0 , dl=dl->next, --sel), if ( dl'=NULL ) DocSetShowSelection(dv,dl->page) , } } void XVT_CALLC0NV1 RefByFillup(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) WINDOW refby = xvt_wm_get_ctl (w,RefBy_RefBy) WINDOW downs = xvt_wιn_get_ctl (w,RefBy_Downs) DocPartLink *dl, xvt_lιst_suspend(refby) , xvt_lιst_suspend(downs) , xvt_lιst_clear(refby) , xvt_lιst_clear(downs) , if ( dv->selected==NULL ) xvt_vob 3 _set_tιtle(xvt_wm_get_ctl (w, RefBy_RelUrl) , " ' ) , else { xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl(w, RefBy_RelUrl) , dv->selected->tιtle'dv->selected->tιtle dv->selected->relurl) , for ( dl = dv->selected->downε, ι=0, dl'=NULL, dl = dl->next ) xvt_lιst_add(downs, ι++,dl->page->tιtle'dl->page->title dl->page->relurl) for ( dl = dv->selected->refered_by, ι=0 dl '=NULL dl = dl->next ) xvt_lιst_add(refby,ι++,dl-:>page->tιtle'dl->page->title dl->page->relurl) } xvt_lιs _resume(downε) , xvt_lιst_resume(refby) } void XVT_CALLCONVl RefBySize(WINDOW w) { RCT newsize, subsize, cu, WINDOW re by = xvt_wιn_get_ctl(w,RefBy_RefBy) , WINDOW downs = xvt__wιn_get_ctl(w,RefBy_Downs) , WINDOW dismiss = xvt_wιn_get_ctl(w,RefBy_Dιsmιss) WINDOW copyurl = xvt_wm_get_ctl(w,RefBy_CopyUrl) , int vdiff, hdiff, xvt_vob 3 _get_clιent_rect(w,tnewsize) , xvt_vob 3 _get_outer_rect(copyurl,tcu) , hdiff = newsize.right- (cu rιght+10) , xvt_vob 3 _get_outer_rect(refby,tsubsize) vdiff = newsize.bottom- (subsize.bottom+10) , subεize top += vdιff/2, subsize.bottom += vdiff, subsize right += hdiff, if ( subsize.bottom<subsιze.top+20 | | subsize rιght<subsιze left+30 ) { xvt_vob 3 _get_outer_rect(w,tnewsize) , if I subsize πght<subsιze.left+30 ) newsize.right += subsize.left+30 - subsize right, if ( subsize.bottoπvesubsize.top+20 ) newsize.bottom += subsize.top+20 - subsize bottom, docrafar.c Sat Mar 18 17:32:24 1995 4 xvt_vobj_move(w,inewsize) ; } else { xvt_vobj_move(refby,tsubsize) ; xvt_vobj_get_outer_rect(downs,tsubsize) ; subsize.bottom += vdiff/2; subsize.right += hdiff; xvt_vobj_move(downs,tsubsize) ; xvt_vobj_get_outer_rec (dismiss,tsubsize) ; subsize.left += hdiff; subsize.right += hdiff; xvt_vobj_move(dismiss,tsubsize) ; cu.left += hdiff; cu.right += hdiff; xvt_vobj_move(copyurl,tcu) ; void XVT_CALLCONVl DocShowReferencedBy(WINDOW w) { DocView *dv = (DocView *) xvt_vobj_get_data(w) ; if ( dv->referenced_by != NULL_WIN ) navi_vobj_raise(dv->referenced_by) ; else if (( dv->referenced_by = xvt_win_create_res(RefBy, TASK_WIN, EM_ALL, RefBy_eh, (long) dv ))==NULL_WIN ) xvt_dm_post_error("Can't open window"),- } void XVT_CALLCONVl DocDeεtroyRefBy(WINDOW w) { DocView "dv = (DocView *) xvt_vobj_get_data(w) ,- dv->referenced_by = NULL_WIN; xvt_vobj_destroy(w) ,- ) docview.c Sun Mar 19 18:03:01 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved. ' ♦include <xvt.h> ♦include <statbar.h> ♦include "NaviPres.h" ♦include "keymore.h" ♦include "func.h" ♦include "html.h" ♦include "doc.h" ♦include "str.h" ♦include "view.h" ♦include "crud.h" ♦include "callback.h" ♦include "xlocal.h" ♦include "guess.h" ♦include "weblet.h" ♦include "cursors.h" static int scrollbar_wιdth = 0, static long XVT_CALLC0NV1 DocSub_eh(WINDOW w, EVENT "event) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ,- switch ( event->type ) { case E_UPDATE: DocDrawfdv,tevent->v.update.ret) ; break; case E_HSCR0LL: DocHScroll (w,event) ; break,- case E_VSCR0LL: DocVScroll(w,event) , break; case E_MOUSE_MOVE • DocMouseMove(w,event) ,- break, case E_MOUSE_UP: DocMouseUp(w,event) , break; case E_MOUSE_DOWN • ♦if XVTWS==MTFWS DocPaneFocus(w,true) ; Winfolnviεible() ; DocMouseDown(w,event) ; break; case E_MOUSE_DBL: DocMouseDbl (w,event) ; break; case E_CHAR: DocChar( ,event) ; break; case E_FOCUS: DocPaneFocus(dv->w,event->v.active) , break,- default: break; ) return 0L; void XVT_CALLC0NV1 DocSetMenu(DocView *dv) { int paste_enable; xvt_menu_εet_ιtem_enabled(dv->w,All_Copy,dv->εelected'=NULL) , docview.c Sun Mar 19 18:03:01 1995 2 xvt_menu_set_ιtem_enable (dv->w,All_Cu , dv->selected!=NULL ti (dv->selected->loaded==NULL || 'dv->selected->loaded->nonaune )), xvt_menu_set_ιtem_enabled(dv->w,DocumentMenu_Clear,dv->selected'=NULL) ; paεte__enable = navι_cb_has_format(CB_APPL, "LINK" ) | | navι_cb_has_format(CB_APPL, "XLNK") ; xvt_menu_set_ιtem_enabled(dv->w,All_Paste,pas e_enable) ,- xvt_menu_set_ιtem_enabled(dv->w,All_PasteURL,paste_enable) , /* Copy URL is always meaningful */ ) void XVT_CALLC0NV1 DocPaneFocus(WINDOW w, int gaιned_focus) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) ; if ( gaιned_focus ) { ♦if (XVTWS '= MACWS it XVTWS '= WINWS) tt defιned(PageMenu_Bookmarks) if ( dv->wιndowmenu_dιrty ) { MENU_ITEM 'menubar. Old, "freeme, old = menubar = xvt_menu_get_tree(dv->w) , menubar = DocSetWindowMenus(dv,menubar,ifreeme) , xvt_menu_set_tree(dv->w,menubar) ,- xvt_reε_free_menu_tree(old) ; if ( oldi=menubar ) xvt_mem_free( (DATA_PTR(menubar) ; } ♦endif ♦if XVTWS!=MTFWS Winfolnvisible() ; ♦endif DocSetMenu(dv) ; } } DocView * XVT_CALLC0NV1 newϋocViewtDocument *doc) { DocView "dv = (DocView *) myalloc(sizeof (DocView) ) , doc->docvιew = dv; dv->doc = doc; dv->wmdowmenu_dιrty = true; dv->curl = dv->maxl = -1, dv->reductιon = 1, dv->expansιon = 1; dv->tag = TAG_DOCUMENT; return dv, ) void XVT_CALLCONVl DocHeadDraw(WINDOW w, RCT *rct) { char buffer[40] ; RCT test,res,pos,dest, static XVT_IMAGE clean, dirty; DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ; test.top = 0; test.left = 0; test.rιght=10000, test.bottom = TOOLBAR_SIZE+4 + 32 + 4; /"if ( rct->rιght==0 it rct->bottom==0 )*/ /* Hunh' Why do we get these' "/ "ret = test, /* display rectangle is just wrong */ xvt_dwιn_get_font_metπcs(w,tld,tas,ids) ; if ( clean==NULL_IMAGE ) { clean = xvt_res_get_ιmage(1200) ; dirty = xvt_res_get_ιπιage(1210) , docview. c Sun Mar 19 18 :03 :01 1995 3 if ( xvt_rect_ιntersect ( ires , ttest , ret ) ) ( xvt_dwιn_clear (w, COLOR_LTGRAY) ; xvt_vob 3 _get_tιtle (xvt_wιn_get_ctl (w, Doc_FιrstText ) . buf fer , sizeof (buffer ) ) , ♦if XVTWS==MTFWS xvt_dwιn_draw_text (w, 32+8+8 , TOOLBAR_SIZE+4+as+9 , buf fer , -l ) ; ♦el i f XVTWS==WINWS xvt_dwm_draw_text (w, 32+8+8 , TOOLBAR_ΞIZE+4+as+2 , buf fer , -1 ) , ♦else κvt_dwιn_draw_text(w,32+8+8,TOOLBAR_SIZE+4+as+6,buffer, -1) , ♦endif pos.lef = 0; pos.right = 32; pos.top = 0, pos.bottom = 26; dest left = 8; dest.right = 8+32, dest.top = TOOLBAR_SIZE+ , dest.bottom = dest.to P+26; xvt_dwιn_draw_ιmage(w,dv->doc->anydιrt'dirty:clean,tdes ,tpoε) , ) } void XVT_CALLC0NV1 DocDirtCheck(Document *doc) { int changed = doc->d rty; DocPart *dp; lf ( 'changed ) for ( ; dp'=NULL , dp = dp->another ) if ( dp->loaded'=NULL tt dp---loaded---changed ) { changed = true; break; } if ( changed '= doc->anydιrt ) { doc->anydιrt = changed; if ( doc->docvιew'=NULL ) { RCT ret; ret.left = 8; ret.right = 8+32, ret.top=TOOLBAR_SIZE+4; ret.bottom = rct.top+32, DocHeadDraw( doc->docvιew->w,tret ), } ) ) void XVT_CALLC0NV1 DocViewDelete(WINDOW w) { DocWindowDies(w) ; ) void XVT_CALLC0NV1 DocViewClose(WINDOW w) { DocView "dv = (DocView *) xvt_vob;__get_data(w) , DocClose(dv->doc) ,- } void XVT_CALLC0NV1 DocViewHide(WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) , dv->doc->docvιew = NULL; xvt_vob 3 _destroy(dv->w) ; ) static void ArrangeDocCllentArea(WINDOW w, RCT *r) ( RCT cr; if( !scrollbar_wιdth) scrollbar_wιdth = xvt_vob 3 _get_attr(NULL_WIN, ATTR_CTL_VERT_SBAR_WIDTH) , xvt_jvob 3 _get_outer_rect(xvt_wιn_get_ctl(w, Doc_FιrstText) ,tcr) , /* Doc_Fιrst gives the wrong height value because it is a pull down */ r->top = cr.bottom+12, if ( r->top<TOOLBAR_SIZE+32+8 ) docview.c Sun Mar 19 18:03:01 1995 4 r->top = TOOLBAR_SIZE+32+8; r->bottom -= STATUS_BAR_SIZE + scrollbar_wιdth, r->rιght -= scrollbar_wιdth; if I r->bottom<r->top+20 ) r->bottom = r->top+20; ) void XVT_CALLCONVl DocViewFillupFirst(WINDOW w) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ,- Document "doc = dv->doc, WINDOW first = xvt_wιn_get_ctl (w,Doc_Fιrst) ,- DocPart "dp, xvt_lιst_εuspend(first) , xvt_lιst_clear(flrεt) , sel = -1; for ( dp = doc->first, i = 0; dp'=NULL, dp = dp->another ) { if ( I 'dp->extemal ii pmatch(dp->contenttype, "text/html" ) ) | | dp==doc->first) { xvt_lιst_add(first, l,dp->tιtle'dp->title • dp->relurl) , ++ι , } } if I sel== -1 ) sel = i, if I doc->fιrst'=NULL 1 xvt_lιst_set_sel I irst, 0, true) , xvt_lιst_resume(first) , DocPaneFocus(w, true) , ) void DocViewFillupName(DocView "dvl { Document "doc = dv->doc, char buffer[200] ; xvt_res_get_str(Chooser_Web,buffer,sizeo (buffer) ) , if ( strlen(doc->name)>150 ) sprintf(buffer+strlen(bufter) , " . % 150s", fsys_nametaιl (doc->name) ) , else sprint!(buffer+εtrlen(buffer) , " %s' , doc->name) , DocWιndowSetTιtle(dv->w,buffer) , navι_wm_εet_ιcon_name(dv->w, fεyε_naunetaιl2(doc->naune) ) , ) void XVT_CALLCONVl DocViewFlllup(WINDOW w) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , Document "doc = dv->doc; RCT cr, int width, off, char buffer[40] ; static WIN_DEF wιn_desc[ )= { {W_PLAIN, (0,0,10,10) , "" ,U_PIXELS } , {0} 1, DocWιndowBom (w) , dv->w = w, xvt_vob 3 _get_clιent_rec (w,twιn_desc[0] .ret) , xvt_vob]_get_tιtle(xvt_wιn_get_ctl (w, Doc_FιrstTex ) ,buffer, sizeof(buffer) ) xvt_vob 3 _set_vιsιble(xvt_wιn_get_ctl(w, Doc_FιrεtText1 , falεe) , docview.c Sun Mar 19 18:03:01 1995 5 width = xvt_dwιn_get_text_wιdth(w,buffer,-1) , xvt_vob 3 _get_outer_rect(xvt_wιn_get_ctl (w, Doc_Fιrst) ,tcr) , off = 0, if ( cr.bot om-cr.top<32 ) off = (32- (cr.bottom-cr.top) ) 12; cr.bottom += TOOLBAR_SIZE+4+off-cr.top; cr.top = T00LBAR_SIZE+4+off, cr.right = wm_desc[0] .ret.rιght-10; cr.left = 8+32+8+wιdth+4, xvt_vob 3 _move(xvt_wm_get_ctl(w, Doc_Fιrst) ,tcr) ; ArrangeDocClientArea (w, twm_desc[0] .ret) , wm_desc[0] .v. win. flags = WSF_HSCROLL|WSF_VSCROLL, dv->wιdth = wιn_desc[0] .ret .right - wm_desc [0] .re . lef t; dv->heιght = wιn_desc [0] .ret .bottom - wιn_desc [0] .ret . op, dv->pane = xvt_wιn_create_def (wιn_deεc, w, EM_ALL, DocSub_eh, (long) dv) , xvt_dwιn_set_back_color (dv->pane, bg_col ) , xvt_dwιn_set_fore_color (dv->pane, fg_col) , ♦ifdef ATTR_XOR_REF_COLOR xvt_vobj_set_attr (dv->pane, ATTR_XOR_REF_COLOR, bg_col ) ; ♦endif wιn_desc [0] . v.win. f lags = 0, wιn_desc [0] .ret . top = wm_desc[0] ret .bottom+scrollbar_wιdth, in.desc [0] .ret. bottom = wm_desc [0] . ret . top + STATUS_BAR_SIZE, wιn_deεc [0] .ret . right += εcrollbar_wιdth, dv->stat = xvt_wιn_create_def (wιn_desc,w, EM_ALL, Stat_eh, (long) dv) ; Statlmt (dv->εtat) , DocViewFillupName(dv) , /* xvt_menu_set_ιtem_checked(w,DocumentMenu_Tree,doc->graph_type==g_tree) , xvt_menu_set_ιtem_checked(w,DocumentMenu_Web,doc->graph_type==g_web) , */ xvt_menu_set_ιtem_enabled(w,DocumentMenu_Reduce,dv->reductιon<16) , xvt_menu_set_ιtem_enabled(w,DocumentMenu_Enlarge,dv->reductιon>l) , DocScrollSync(dv) ; DocViewFillupFirεt(w) , DocVιewDoUεerPlaced(doc) , DocRegraph(dv,doc->graph_type) , DocStdMsg(dv) , AπySetStopButton! (View *) dv,NULL), ♦if 0 /* does this stop focus-steal' */ ♦if XVTWS==MTFWS navι_set_doc_focus_pane(w,dv->pane) , ♦else navι_set_wιn_focus_pane(w,dv->pane) , ♦endif ♦endif ) void XVT_CALLC0NV1 DocViewSize(WINDOW w) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , RCT newsize, panesize, first, int woff; xvt_vob 3 _get_clιent_rect(w,tnewsize) ; xvt_vob 3 _get_outer_rect(xvt_wιn_get_ctl(w,Doc_Fιrst) ,tfιrst) , if ( first.bottom 0 ) /* XVT bug, this shouldn't happen */ first.bottom = 10*xvt_vob 3 _get_attr(NULL_WIN,ATTR_CTL_STATIC_TEXT_HEIGHT) woff = (newsize.rιght-10) -first.right, panesize = newsize, docview.c Sun Mar 19 18:03:01 1995 6 ArrangeDocClientArea(w,tpanesize) , first.right += woff; if ( panesize.top+30>=panesιze.bottom || first.left+30>=fιrst.right ) { /* Got too small */ xvt_vob 3 _get_outer_rec (w,tnewsize) ; if ( first.left+30 >= first.right 1 newsize.right += first.left+100-first.right, if ( panesize.top+30 >= panesize.bottom ) newsize.bottom += panesize.top+30-panesize.bottom, xvt_vob 3 _move(w,tnewsize) ,- } else if ( dv->wιdth'=panesιze.right-panesize.lef || dv->heιght!=panesιze.bottom-panesιze.top ) { xvt_vob 3 _move(dv->pane,ipanesize) , xvt_vob 3 _move(xvt_wιn_get_ctl (w,Doc_Fιrst) ,ifirst) ; dv->wιdth = panesize.r ght-panesize.left; dv->heιght = panesize.bottom-panesize.top; DocScrollSync(dv) ,- paneεize.top = panesize.bottom+scrollbar_wιdth, panesize.bottom = panesize.top+ STATUS_BAR_ΞIZE, panesize.right += scrollbar_wιdth; xvt_vob 3 _move(dv->sta .tpanesize) , ) void XVT_CALLC0NV1 DocChar(WINDOW w, EVENT "event) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , swιtch(event->v.chr.ch) { case K_C0PY. if ( event->v.chr.control ) DocCopyURL(dv->w) ; else DocCopy(dv->w) ; break, case K_PASTE DocPaste(dv->w) ,- break,- case K_CUT DocCut(dv->w) ; break, case K_xOPEN: AnyOpen(dv->w) , break, case K_xSTOP: AnyStopComm(dv->w) ; break; case '\177': case 'H'-'β'- DocClear(dv->w) , break, case 'T'-'θ' : DocWinTemplate(w) ; break; default xvt_scr_beep() ; ) ) void XVT_CALLC0NV1 HighlightDocPart(DocView "dv, DocPart "page) { RCT ret; DRAW_CTOOLS ctooIs,new, • ret.left = (page->bb.left/dv->reductιon)-dv->offieft, ret.right = (page->bb.πght/dv->reductιon)-dv->offlef , docview.c Sun Mar 19 18:03:01 1995 7 ret. op = (page->bb.top/dv->reduction)-dv->offtop; ret.bottom = (page->bb.bottom/dv->reduction)-dv->offtop; xvt_dwin_get_draw_ctools(dv->pane,tctools) ; new = ctools; new. ode = M_XOR; new.brush.pat = PAT_S0LID; new.brush.color = new.fore_color; new.pen.pat = PAT_H0LL0W; xvt_dwin_set_draw_ctools(dv->pane,tnew) ,- xvt_dwin_draw_rect(dv->pane,irct) ; xvt_dwin_set_draw_ctools(dv->pane,tctools) ; } void XVT_CALLC0NV1 OutlineDocPart(DocView "dv, DocPart "page) { RCT ret; DRAW_CTOOLS ctools,new; ret.left = (page->bb.left/dv->reduction)-dv->offieft; ret.right = (page->bb.right/dv->reduction)-dv->offieft,- ret.top = (page->bb. oρ/dv->reduction)-dv->off op; ret.bottom = (page->bb.bottom/dv->reduction)-dv->off op; xvt_dwin_get_draw_c oolε(dv->pane,tctools) ; new = ctools; new.mode = M_XOR; new.brush.pat = PAT_HOLLOW; new.brush.color = new.fore_color; new.pen.pat = PAT_S0LID; xvt_dwin_set_draw_ctools(dv->pane,inew) ; xvt_dwin_draw_rect(dv->pane,tret) ; xvt_dwin_set_draw_ctoolε(dv->pane,tctools) ; ) void XVT_CALLC0NV1 DocSetSelection(DocView "dv, DocPart "dp) { if ( dp == dv->selected ) return; if ( dv->selected != NULL it !dv->selected->hidden ) HighlightDocPart(dv,dv->selected) ,- if ( dp != NULL ti !dp->hidden ) { HighlightDocPart(dv,dp) ; if ( dv->reduction==l ) { DRAW_CTOOLS old,new; char "pt; pt = fsys_naunetail(dp->relurl) ; xvt_dwin_get_draw_ctools(dv->pane,told) ; new = old; ne .opaque_text = true,- if ( !bw_display it localcolours[dp->external] !=new.fore_color ) new.fore_color = localcolours[dp->external] ; xvt_dwin_set_draw_ctools(dv->pane,tnew) ,- xvt_dwin_draw_text(dv->pa_ne,dp->tbb.left-dv->offieft,dp->tbb. op-dv->offtop+dp ->as, pt,-l); xvt_dwin_set_draw_ctools(dv->pane,told) ,- } } dv->selected = dp; if ( dv->refers_to ) RefToFillup(dv->refers_to) ; if ( dv->referenced_by ) RefByFillup{dv->referenced_by) ; DocSetMenu(dv) ; xvt_menu_update(dv->w) ; docview.c Sun Mar 19 18:03:01 1995 8 void XVT_CALLCONVl DocShowPart(DocView "dv, DocPart "dpi { RCT "bb; if ( dv==NULL ) return; if ( dp->bb.top*dv->reductιon<dv->off op | | dp->tbb.bottom*dv->reductιon>dv->off op+dv->heιght ) DocSetVScroll(dv,dp->bb.top*dv->reductιon-dv->heιght/16) ; bb = tdp->tbb; if ( bb->left>dp->bb.left ) bb = tdp->bb; if ( bb->left*dv->reductιon<dv->offlef | | bb->bottom*dv->reductιon>dv->offieft+dv->wιdth ) DocSetHScroll(dv,bb->lef *dv->reductιon-dv->wιdth/16) , } void XVT_CALLCONVl DocSetShowSelection(DocView *dv, DocPart *dp) ( if I dv==NULL | | dp == dv->selected 1 return; DocShowPar Idv,dp) , DocSetSelectionldv,dp) , } void XVT_CALLC0NV1 DocMouseDown(WINDOW w, EVENT "event) { DocView "dv = (DocView *) xvt_vob]_get_data(w) ; xvt_wm_trap_poιnter(dv->pane) ; DocMouseMovetw,even ) , /* Sometimes xvt loses motion events */ DocSetSelection(dv,dv->undercursor) , if ( dv->undercursor'=NULL 1 { dv->off__x = even ->v.mouse.where.h+dv->offleft-dv->undercursor->bb.le t/dv->reduct dv->off_y = event->v.mouse.where.v+dv->offtop-dv->undercurεor->bb.top/dv->reductιo n; ) else { dv->off_x = -1; dv->off_y = -1; } dv->clιckcnt = true; dv->mousedown = true; dv->presε_pnt = event->v.mouse.where, } void XVT_CALLCONVl DocMouseDbl (WINDOW w, EVENT "event) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ; dv->cl ckcnt = 2, dv->mousedown = true; ) void XVT_CALLC0NV1 DocMouseUp(WINDOW w. EVENT "event) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , char "buffer, "url; mt diff, sizebuf; View "vs; xvt_wιn_release_poιnter() ,- DocMouseMove(w,event) ; /* Sometimes xvt loses motion events */ if ( !dv->mousedown ) return; /* Random stray event, down was in another window */ dv->mousedown = false, diff = abs(dv->press_pnt.h - even ->v.mouεe.where.h) + abs(dv->press_pnt.v - event->v. ouεe.where.v) ; docviaw.c Sun Mar 19 18:03:01 1995 if ( dv->draggιng it dιff>=6 ) { OutlineDocPart (dv,dv->undercursor) , dv->draggmg = false; dv->undercursor->userplaced = true, DocSetDirty(dv->doc) ; DocUpdatePane(dv->doc) ,- } else if ( dv->draggιng ) { OutlineDocPar (dv,dv->undercursor) , dv->draggιng = falεe; ) else if ( dv->drag_out ) { PNT from, View "newview, dv->drag_out = false, xvt_wιn_set_cursor (dv->pane, CURS0R_ARR0W) , from = event->v.mouse.where, xvt_vob 3 _translate_pomts (dv->pane, SCREEN_WIN, ifrom, 1) , newview = VιewWιnFmdVιew( (View *) dv, from.h, from v) , /* Abort any communication which plans to draw into this window */ if ( newview' =NULL ) CrudForVie (newview, abort_get_local ,NULL) url = buffer = myalloc (sizebuf=strlen(dv->doc->name) +strlen(dv->selected->relurl) + 30) , if ( ' fsyε_ιs_url (dv->selected->relurl) ) fsys_buιld_name(dv->doc->name,dv->selected- >relurl, buffer, sizebuf) , else url = dv->selected->relurl, if ( newview '= NULL it newvιew->tag==TAG_DOCUMENT ) DocAddPageName (( (DocView *) newview) ->doc,url , -1 , -1 ) , else OpenUR (url, newvιew==NULL' (View *) dv:newvιew, newvιew==NULL, OPEN_DEFAULT, false,dv->doc->name) ; myfree (buffer) ; } if ( dv->clιckcnt == 0 ) re urn; if ( dv->clιckcnt==2 tt dv->selected' =NULL tt 'event->v mouse control ) { if ( dv->selected->loaded ) ( for ( vs=dv->selected->loaded->vιews, vs'=NULL, vs=vs->nextsame ) if ( (View *) xvt_vob 3 _get_data (vs->w) ==vs ) break, if ( vs ' =NULL ) { navι_vob 3 _raιse(vs->w) , ) else CreatePageWιn(dv->selected->loaded) , ) else if ( dv->selected->exιsts tt pmatch! "application/x-navimap" ,dv->selected->contenttype) ) ( if ( 'xvt_wιn_create_res(Map, TASK_WIN, EM_ALL, Map_eh, MapGetlnit (NULL,dv->doc,dv->selected->relurl) ) ) xvt_dm_post_errorI "Can' open window"), } else if ( dv->selected->exιstε | | pmatch! "text/html" ,dv->selected->contenttype) ) { /* Create it if it don't exist and is html */ if ( fsyε_ιs_url (dv->selected->relurl) ) OpenURL(dv->selected->relurl , (View *) dv, true, OPEN_DEFAULT, false,dv->doc- +strlen(dv->selected->relurl fsys_buιld_name(dv->doc->name,dv->selec ed->relurl,buffer, sizebuf ) , OpenUR (buffer, (View *) dv, rue,OPEN_DEFAULT, false, v->doc->name) , myfree (buffer) , docview.c Sun Mar 19 18:03:01 1995 10 } ) else if ( dv->clιckcnt==2 tt dv->selected'=NULL tt event-> .mouse.control ) { DocCopyURL(w) , ) /* ' ' ' ' */ dv->clιckcnt = 0; } void XVT_CALLC0NV1 DocSetMessage(DocView "dv, char "msgl { if ( msg==NULL ) msg="", if (dv it dv->w) Sta SetMessage(dv->s at,dv->εtat_text,msg) , ) void XVT_CALLC0NV1 DocStdMsg(DocView *dv) { DocSetMessage(dv, " " ) ; } void XVT_CALLC0NV1 DocSetDirty(Document *doc) { if ( 'doc->dιrty ) { doc->dιrty = true, DocDirtCheck(doc) , ) ) void XVT_CALLC0NV1 DocDirtySave(Document "doc) { QueueDocSave(doc,NULL) , ) void XVT_CALLC0NV1 DocMouseMove(WINDOW w, EVENT "event) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , Document "doc = dv->doc, int x,y; DocPart "old. "page, int off_x, off_y, static WINDOW oldw; static mt width, height, if ( dv->mousedown ) { if I dv->undercursor==NULL | | dv->off_x==-l ) return, if ( dv->draggιng ) OutlineDocPar (dv,dv->undercursor) ; p = event->v.mouεe.where, xvt_vob 3 _tranεlate_poιn ε(dv->pane,dv->w,tp,1) , if ( oldw'=dv->w ) { RCT r; xvt_vob 3 _get_clιent_rect(dv->w,tr) , oldw = dv->w; width = r.right; height = r.bottom; ) if ( p.h<0 I I p.v<0 I I p.h>=wιdth | | p.v>=heιght ) { if ( 'dv->drag_out ) { navι_set_cursor(dv->pane,cursor_FOLLOWLINK) , dv->drag_out = true; /* Restore to original location "/ off_x = (dv->press_pnt.h-dv->off_x+dv->offleft) *dv->reductιon - dv->underc ursor->bb.left; off_y = (dv->press_pnt.v-dv->off_y+dv->off op) *dv->reductιon - dv->undercu rsor->bb top, dv->undercursor->bb.lef += off_x; dv->undercursor->bb.right += off_x, dv->undercursor->bb.top += off_y; dv->undercurεor->bb.bottom += of _y, dv->undercurεor->tbb left += off_x, dv->undercursor->tbb.right += off_x, dv->undercursor->tbb.top += off_y, dv->undercursor->tbb.bottoπ += off_y, docview.c Sun Mar 19 18:03:01 1995 11 ) dv->draggιng = false, ) else { if ( dv->drag_out ) { xvt_wm_set_cursor(dv->pane,CURSOR_ARROW) ; dv->drag_out = false, } dv->draggιng = true; off_x = (event->v.mouse.where.h-dv->off_x+dv->offie t) *dv->reductιon - dv->und ercursor->bb.left; off_y = (event->v.mouse.where.v-dv->off_y+dv->off op) *dv->reductιon - dv->unde rcursor->bb.top, dv->undercurεor->bb.left += off_x; dv->undercursor->bb.right += off_x, dv->undercursor->bb.top += off_y; dv->undercursor->bb.bottom += off_y, dv->undercursor->tbb.lef += off_x; dv->undercursor->tbb right += off_x, dv->undercursor->tbb.top += off_y; dv->undercurεor->tbb.bottom += of _y; OutlineDocPart(dv,dv->undercursor) , ) 1 else { oldw = NULL_WIN, x = (event->v.mouse.where.h+dv->offleft) *dv->reductιon, y = (event->v.mouse.where.v+dv->offtop) *dv->reductιon, old = dv->undercursor; if ( old '=NULL it old->bb.left<=x tt old->bb.rιght>=x it σld->bb.top<=y ti old->bb.bottom+15>=y ) return; /* Old thing is good */ dv->undercursor = NULL; for ( page = doc->fιrεt, page'=NULL; page=page->another ) if ( x>=page->bb.le t tt x<page->bb right tt y>=page->bb.top tt y<page->bb bottom+15 ) { dv->undercurεor = page, /"break;*/ /* Two may be piled on top of each other, the one */ /* drawn laεt (further down the list) is the one that */ /* will show, so keep going. */ ) if ( old == dv->undercursor ) return, if ( dv->undercursor==NULL ) DocStdMsg(dv) , else if ( dv->undercursor->tιtle'=NULL tt *dv->undercursor->tιtle'=' \0' ) DocSetMessage(dv,dv->undercursor->tιtle) , else DocSetMessage(dv,dv->undercursor->relurl) , } } void XVT_CALLC0NV1 DocScrollSync(DocView *dv) { mt redheight = dv->totheιght/dv->reductιon, int redwidth = dv->totwιdth/dv->reductιon; if ( dv->offtop+dv-.-height > redheight ) dv->offtop = redheιght-dv->heιght, if ( dv->offleft+dv->wιdth > redwidth ) dv->offleft = redwιdth-dv->wιdth, if ( dv->offtop < 0 ) dv->offtop = 0, if ( dv->offleft < 0 ) dv->offleft = 0, /* scroll bars disappear on Windows if prop == range */ if ( ) redheight = dv->heιght+l, if ( redwidth = dv->wιdth+l, xvt_sbar_set_range(dv->pane,VSCROLL,0,redheight) , xvt_sbar_set_proportιon(dv->pane,VSCROLL,dv->heιght) ; xvt_sbar_set_pos(dv->pane,VSCROLL,dv->offtop) ; xvt_sbar_set_range(dv->pane,HSCROLL, 0,redwidth) , docview.c Sun Mar 19 18:03:01 1995 12 xvt_sbar_set_proportιon(dv->pane,HSCROLL,dv->wιdth) ; xvt_sbar_set_pos(dv->pane,HSCROLL,dv->offleft) , } void XVT_CALLCONVl DoeSetVScroll(DocView "dv, int newoff) { RCT size; long diff; if I newoff>dv->totheιght/dv->reductιon-dv->heιght ) newoff = dv->totheιght/dv->reductιon-dv->heιght; if I newoff<0 ) newoff = 0; if ( newoff==dv->offtop ) return; xvt_dwιn_update(dv->pane) ; xvt_vob 3 _get_clιent_rect(dv->pane,tsize) ; diff = dv->offtop-newoff; dv->offtop = newoff; xvt_dwιn_scroll_rect(dv->pane,tsize, 0, lint) diff), xvt_εbar_set_pos(dv->pane,VSCROLL, dv->off op) , void XVT_CALLC0NV1 DocSetHScroll (DocView "dv, int newoff) ( RCT size; long diff; if ( newoff>dv->totwιdth/dv->reductιon-dv->wιdth ) newoff = dv->totwιdth/dv->reductιon-dv->wιdth; if ( newoff<0 ) newoff = 0; if ( newoff==dv->offieft ) return, xvt_dwιn_update(dv->pane) ; xvt_vob 3 _get_clιent_rec (dv->pane,tsize) ; diff = dv->offleft-newoff; dv->offleft = newoff; xvt_dwm_scroll_rect(dv->pane,tsize, dnt) diff.O), xvt_sbar_set_pos(dv->pane,HSCROLL, dv->offlef ) ; ) static int XVT_CALLCONVl DocIncVScroll (DocView "dv, EVENT "event) I switch! event->v.scroll.what ) { default: case SC_NONE: return 0; case SC_LINE_UP: return -13; case SC_LINE_DOWN ■ return 13; case SC_PAGE_UP: return -dv->heιght; case SC_PAGE_DOWN: return dv->heιght; case SC_THUMB. case SC_THUMBTRACK: return! event->v.scroll.pos-dv->offtop) ; } ) static int XVT_CALLC0NV1 DocIncHScroll(DocView "dv, EVENT "event) { swιtch( event->v.scroll.what ) ( default: docviaw. c Sun Mar 19 18 : 03 :01 1995 13 case SC_NONE : return 0 , case SC_LINE_UP : return -13 ; caεe SC_LINE_DOWN : return 13 ; caεe SC_PAGE_UP : return -dv->wιdth; case SC_PAGE_DOWN: return dv->wιdth; case SC_THUMB: case SC_THUMBTRACK: return! event->v.scroll.pos-dv->offleft) ; ) } void XVT_CALLC0NV1 DocHScroll(WINDOW w, EVENT "event) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , DocSetHScroll (dv,dv->offleft+DoelncHScroll (dv,event) ) , ) void XVT_CALLCONVl DocVScroll (WINDOW w, EVENT "event) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , DoeSetVScroll(dv,dv->off op+DoelncVScroll(dv,event) ) ; } static void XVT_CALLC0NV1 RedoScrollBars (DocView "dv, int oldred) { dv->offtop = (dv->offtop*oldred) /dv->reduc ion, ■ dv->offleft = (dv->offleft*oldred)/dv->reductιon; DocScrollSync(dv) ; ) void XVT_CALLCONVl DocEnlarge(WINDOW w) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , if ( dv->reductιon<=l ) { xvt_scr_beep() , return; } dv->reduction --,- RedoScrollBars(dv,dv->reductιon+l) , xvt_menu_set_ιtem_enabled(w,DocumentMenu_Reduce,dv->reductιon<16) , xvt_menu_set_ιtem_enabled(w,DocumentMenu_Enlarge,dv->reductιon>l) , DocUpdatePane(dv->doc) ,- } void XVT_CALLC0NV1 DocReduce(WINDOW w) ( DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ; if ( dv->reductιon>=16 ) ( xvt_scr_beep() ; re urn; } dv->reductιon ++; RedoScrollBars(dv,dv->reductιon-l) ,- xvt_menu_set_ιtem_enabled( ,DocumentMenu_Reduce,dv->reduc 1on<16) xvt_menu_set_ιtem_enable (w,DocumentMenu_Enlarge,dv->reductιon>l) DocUpdatePane(dv->doc) , ) void XVT_CALLCONVl DocChangeGraph(WINDOW w, t t) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , Document "doc = dv->doc; docview. c Sun Mar 19 18 : 03 : 01 1995 14 i f I t == -1 ) t = doc- >graph_ type ; / * Clean Up operation * / / " if ( doc->graph_type ' =t ) * / ( doc ->graph_ type = t ; / * xvt_menu_set_ιtem_checked (w, DocumentMenu_Tree , doc->graph_type==g_tree ) xvt_menu_set_ιtem_checked (w, DocumentMenu_Web, doc->graph_type==g_web) ; * / DocReset ( doc ) ; void XVT_CALLCONVl DocHideSel (WINDOW w) { DocView *dv = (DocView *) xvt_vob 3 _get_data(w) ,- if ( dv->selected'=NULL tt 'dv->selected->hιdden ) ( dv->selected->hιdden = true; DocUpdatePane(dv->doc) , ) ) void XVT_CALLC0NV1 DocShowSel (WINDOW w) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , DocPart "dp, mt any; if ( dv->selected'=NULL it dv->selected->hιdden 1 ( dv->selected->hιdden = false; DocUpdatePane(dv->doc) , ) else if ( dv->selected==NULL ) ( any = false; for ( dp=dv->doc->first, dp'=NULL; dp=dp->another ) ( if ( dp->hιdden ) any = true, dp->hιdden = false; ) lf ( any ) DocUpdatePane(dv->doc) ; 1 ) void XVT_CALLC0NV1 DocWithPage(Page "page) { if ( page->doc==NULL it page->docname'=NULL ) page->doc = DocSyncFmd(page->docname,page->vιews) ,- if ( page->doc==NULL ) ( navι_dm_post_error!Docvιew_CantOpenW/*"Can' open mmiweb"*/) return; ) if I page->doc->docvιew'=NULL ) { navι_vob 3 _raιse(page->doc->docvιew->w) ,- } else CreateDocWm(page->doc) ; if(page->doc->docvιew) { DocSetShowSelection(page->doc->docvιew, LookupDocPart(page->doc, page->url)l ,- ) ) void XVT_CALLC0NV1 DocWinFirst(WINDOW w) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) , DocPart "dp; int l, sel ; sel = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,Doc_Fιrεt) 1 ; for I dp = dv->doc->flrεt, l = 0; dp'=NULL; dp = dp->another 1 { if I !dp->external it pmatch(dp->contenttype, "text/html") 1 ( docview.c Sun Mar 19 18:03:01 1995 15 if ( sel==i ) break; ++i ; } } if ( dp!=NULL ) DocChangeFirs (dv->doc,dp) ; else ( IError("Couldn't find first page"); xvt_lιst_set_εel(xvt_wιn_get_ctl(w,Doc_Fιrst) , -1, false) ,- xvt_list_set_sel(xvt_wm_get_ctl (w,Doc_Fιrst) , 0,true) , } DocViewFillupFirεt(dv->w) ; DocRedraw(dv->doc) ,- } void XVT_CALLC0NV1 DocWinTemplate(WINDOW w) { DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ; myfree( dv->doc->template ); dv->doc->template = NULL; if ( dv->εelected ) dv->doc->template = copy( dv->selected->relurl ) ; ) void XVT_CALLC0NV1 DocPubllsh(WINDOW w) { char buffer[400] ; DocView "dv = (DocView *) xvt_vob 3 _get_data(w) ,- Document "doc = dv->doc; DocPart "dp; for ( dp=doc->first; dp!=NULL; dp = dp->another ) if ( dp->external it ! fsys_ιs_url(dp->relurl) ) break,- if ( dp!=NULL ) { DocSetShowSelectιon(dv,dp) ; navι_dm_poεt_error(Docvιew_LocalFile, dp->relurl) ; return; } /* brother, have you been saved? */ lf( !DocCommit(doc) ) return; if ( GetDest(Docvιew_Server/*"Specify a server on which to publish the miniweb..."*/, buffer,sizeof(buffer) ) ) { strcat(buffer, "/Load/Doc/"),- strcat (buffer, fsys_nametail(doc->name) 1 ; PublishDoc(doc, buffer, true); } } WINDOW CreateDocWin(Document *doc) { if( !doc) return NULL_WIN; if(doc->docview tt doc->docvιew->w) { return doc->docvιew->w; ) else ( WINDOW w = navi_xvt_wιn_create_res(DocWin, TASK_WIN, EM_ALL, DocWιn_eh, (long)newDocView(doc) ) ; if( !w) xvt_dm_post_error( "Can't open window" ) ; docview. c Sun Mar 19 18:03:01 1995 16 return w; ) navilink.c Tua Mar 7 17:51:44 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved */ ♦include <xvt.h> ♦include "func.h" ♦include "NaviPres h" ♦include "html.h" ♦include "view.h' ♦include "callback.h" struct navilink { View "view, /* anchors are sorted by maximum weight of any url */ struct anchor { int pnum, offset, length, char "anchor, /* urls are sorted by weight */ char ""urls, char *"titles, char **showurl, int umax, ucnt, int done /* Has this anchor been transformed' */ ) "anchors, mt amax, acnt int bad, /* Parse failure */ int dent /* Number of things we have done */ t deadview, ), static void freenl (struct navilink *nl) { int ι, 3 , for ( ι=0, κnl->acnt, ++ι ) { for ( 3=0, 3 <nl->anchors[l] -ucnt, ++ 3 ) { my reelnl->anchors[1] .urls[3] ) , myfreelnl->anchors[1] titles(3] ) , my ree(nl->anchorε[1] showurl [ 3 ]), } myfree(nl->anchors[1) .urls) , myfree(nl->anchors[1] titles), myfree(nl->anchors[1] .showurl), myfree(nl->anchors[1] anchor), ) myfree(nl->anchors) , myfree(nl) , ) /* /* navilinkmgill is a daemon that takes -p portnum as an argument and /* w ll sit waiting for connections It expects pages to be PUT to it /* and sends back application/x-navilmks One line per navilink where a /* line lε a comma separated list of /* /* pnum, start, length, weight, URL /* /* Currently they're sorted by weight. */ static struct navilink "buildnl(struct cstr "rε, View "view) { struct navilink "nl = (struct navilink *) myalloc (sizeof(struct navilink)) int pnum, offset, len, float weight, char "url, char buffer[500] , int 1, char "pt, "start, "end, navilink.c Tua Mar 7 17:51:44 1995 2 VPara *vp, if ( nl==NULL ) return ( NULL 1 ; nl->vιew = view, /* Parse the data stream */ while ( RsGetLine(rs,buffer.sizeof(buffer) 1 >= 0) { url = NULL, if ( sscanf(buffer, "%d,%d,%d,%f" , tpnum, ioffset, tlen, tweιght)==4 ) f url = strchr(strchr(strchr(strchr(buffer, ', ' )+1, ', ' )+1, ', ' )+1, ', '1, if { url'=NULL ) ++url; ) if ( url'=NULL ) { for ( ι=0; κnl->acnt; ++ι ) { if ( nl->anchors Ti] .pnum==pnum tt nl->anchorε[I] offset==offset ) break; } if ( ι==nl->acnt ) { /* New anchor */ if ( nl->acnt>=nl->amax 1 nl->anchors = (struct anchor *) myrealloc(nl->anchorε, (nl->amax+=10) "sizeof(struct anchor) ) , ++nl->acnt, me set(nl->anchors+ι, '\0' ,sizeof(nl->anchors[I] ) ) , nl->anchors[ι] .pnum = pnum, nl->anchors[i] .offset = offset; nl->anchors[l] .length = len, ) if ( nl->anchors [I] .ucnt >= nl->anchors[I] .umax ) { nl->anchors[i) .urlε = (char **) myrealloc(nl->anchors[ι] .urls, (nl->anchors[l] .umax+=10) * sizeof (char *)), nl->anchors[i].titles = (char ") myrealloc(nl->anchors[1] .tit]es, (nl->anchors[l) .umax+=10) * sizeof(char *)), nl->anchors[l] .εhowurl = (char **) myrealloc(nl->anchorε [l].showurl, (nl->anchors [l) umax+=10)* sizeof(char *)), } nl->anchors[i] .urls[nl->anchors(i] .ucnt] = copy(url), if ( RsGetLine(rs,buffer,sizeof (buffer) ) > 0) nl->anchorε [l] .showurl[nl->anchors[1] .ucnt) = copy(buffer) else nl->anchors [ ] .showurl[nl->anchors[I] .ucnt] = copy(nl->anchors I I] urls[nl- >anchorε[l] .ucnt) ) , if ( RsGetLine(rs,buffer,sizeof (buffer11 > 0) nl->anchors[i] .titles[nl->anchors[I] .ucnt] = copy(buffer) , else nl->anchors[i] .titles[nl->anchors[I] .ucnt] = copy(nl->anchorε[i] .urls[nl-> anchors[i] .ucnt] ) , ++nl->anchors[i] .ucnt; } else nl->bad++, ) /* pagesaveback is expected to close the rs, so we don't */ /* Now associate text with the anchors so we can display them nicely */ for ( ι=0; κnl->acnt; ++ι ) { if ( ( vp = ViewGetVPara(view,NULL,nl->anchors [l] .pnum) )==NULL ) { freenl(nl) ; return(NULL) , ) pt = buffer; if ( nl->anchors[l] .offset+nl->anchors[l] .length>vp->para->tlen | | nl->anchors[i] .offset<0 || nl->anchors[I] .length<=0 ) ++nl->bad; navilink. c Tua Mar 7 17 : 51: 44 1995 3 else { start = vp->para->text + nl->anchors[I) offset, end = start+nl->anchors[l] length, while ( start<end ti pt<buffer+sizeof(buffer)-30 ) { if ( *star ==HTML_MARK ) start += Taglncr(start) , else *pt++ = *start++, ) ) •pt = '\0' , nl->anchors[l] .anchor = copy(buffer) , ) return( nl ) , ) static void NvLnkUpdateInfo(struct navilink "info int pnum, int offset, int diff ) { int l, for ( ι=0, κιnfo->acnt, ++ι ) ( if ( mfo->anchors[I] pnum==pnum it ιn o->anchors[I] offset>offset 1 ιnfo->anchors[l] offset += diff, ) } void XVT_CALLCONVl NvLnkChangeAnchor(WINDOW w) { struct navilink "info = (struct navilink *) xvt_vob 3 _get_data(w) , View "view = ιnfo->vιew, int sel = xvt_lιst_get_εel_mdex(xvt_wιn_get_ctl(w,NvLnk_Anchors) 1 WINDOW urls = xvt_wιn_get_ctl (w, NvLnk_URLs ) , mt ι , 3 , for ( ι=3=0 , κιnfo->acnt , ++ι ) { if ( ιnfo->anchors [i j . done==0 ) ( i f ( 3==sel ) break , } } xvt_lιst_suspend(urls) , xvt_l εt_clear(urls) , if I ι==ιnfo->acnt ) { /* We've applied every transformation we can */ xvt_list_add(urls,0, "") , xvt_vob 3 _set_enabled(xvt_wιn_get_ctl(w,NvLnk_Apρly) , false) , xvt_vob3_set_enabled(xvt_wιn_get_ctl(w,NvLnk_Show) , false) ) else { sel = l, for ( l = 0, κιnfo->anchors[sel] ucnt, ++ι ) xvt_lιst_add(urls,l,ιnfo->anchors[sel] .titles[l] ) , VιewShowSelectιon(vιew,ιnfo->anchors[sel] pnum,ιnfo->anchors[sell offset, ιnfo->anchors[sel) .pnum,info->anchors[sel] .offset+ιnfo->anchors[sel] lengt h) xvt_vob3_set_enabled(xvt_wιn_get_ctl(w,NvLnk_Apply) ,true) , xvt_vob3_set_enabled(xvt_wιn_get_ctl(w,NvLnk_Show) ,true) , } xvt_lιst_set_sel (urls,0,true) , xvt_lιst_resume(urls) , } static void XVT_CALLC0NV1 _NvLnkFιllup(WINDOW w,int sel) { struct navilink "info = (struct navilink *) xvt_vob3_get_data(w) , WINDOW euichors = xvt_wιn_get_ctl(w,NvLnk_Anchors) , navilink.c Tua Mar 7 17:51:44 1995 4 mt 1,3,selindex, xvt_lιst_suspend (anchors) , xvt_lιst_clear (anchors) , selindex = 0; for ( ι = 3 = 0, κmfo->acnt, ++ι ) if ( inf o->anchorε [I] .done==0 ) { if ( ι==sel ) selindex = 3 ,- xvt_lιεt_add (anchors , 3 ++ , ιnfo->anchors [ 1 ] anchor) , } if I 3==0 ) xvt_lιεt_add(anchorε, 3++, " "); xvt_lιεt_set_sel (anchors, selindex, true) , xvt_lιst_resume (anchors) , xvt_vob3_set_enabled(xvt_wιn_get_ctl (w,NvLnk_Undo) , mfo->dcnt>0) , NvLnkChangeAnchor (w) , ViewStdMsg (ιnfo->vιew) , ) void XVT_CALLCONVl NvLnkFi Hup (WINDOW w) { _NvLnkFιllup(w, 0) , ) void XVT_CALLC0NV1 NvLnkUndo (WINDOW w) ( εtruct navilink "info = (εtruct navilink *) xvt_vob 3 _get_data(w) , View "view = inf o->vιew; int 1, oldlen; VPara *vp, for ( ι = 0, κιnfo->acnt, + + 1 ) if ( mfo->dcnt == inf o->anchors [1 ) done ) break, if ( vιew->page->undoeε==NULL | | mf o->dcnt==0 | | ι==ιnfo->acnt ) ( xvt_scr_beep() , } else { vp = ViewGetVParatview,NULL, ιnfo->anchors[1] .pnum) , oldlen = vp->para->tlen, vιew->page->frozen = false, ViewUndo(vιew->pane) , vιew->page->frozen = true, NvLnkUpdatelnfodnfo,info->anchors[1] pnum, ιnfo->anchors[1] .offset, vp->para->tlen-oldlen) ; --ιnfo->dcnt; info->anchors[1] .done = 0; _NvLnkFιllup(w,1) , ) ) void XVT_CALLCONVl NvLnkShow(WINDOW w) { struct navilink "info = (struct navilink *) xvt_vob3_get_data(w) , View "view = mfo->vιew; char buffer[200] , frmt[80], int ι, 3 ,k = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,NvLnk_URLs) ) , int sel = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,NvLnk_Anchors) ) , for ( 1=3=0; κιnfo->acnt; ++1 ) ( if ( info->anchors[1] .done==0 ) { if I 3 ==sel ) break, ++3 • ) } OpenURL!info->anchors[ι] showurl [k] .view,true,OPEN_DEFAULT, false navilink.c Tua Mar 7 17:51:44 1995 5 "NaviPress S artLinking") , xvt_res_get_str(Navιlmk_Loadιng,frmt,sizeof(frmt) ) , /* "Loading %s .. * */ sprintf(buffer, frmt,info->anchors[ι] .urls[k] ) ,- ViewSetMessage(view,buffer1 , ) void XVT_CALLCONVl NvLnkDeεtroy(WINDOW w) ( struct navilink 'info = (struct navilink *) xvt_vob3_get_data(w) , View 'view = ιnfo->vιew; if ( 'ιn o->deadvιew ) { vιew->page->frozen = false; ViewSetCursor(view) ; ViewStdMsg(view) , ) reenl(info) ; * • } void XVT_CALLCONVl NvLnkKill(WINDOW w) { struct navilink 'info = (struct navilink *) xvt_vob 3 _get_data(w) , ιnfo->deadvιew = true, xvt_vob 3 _destroy(w) ; } void XVT_CALLC0NV1 NvLnkApply(WINDOW w) { struct navilink 'info = (struct navilink *) xvt_vob3_get_data(w) , View "view = ιnfo->vιew, int sel = xvt_lιst_get_sel_ ndex(xvt_wιn_get_ctl (w,NvLnk_Anchors) ) , mt 1,3, int k = xvt_lιst__get_sel_ιndex(xvt_wιn_get_ctl(w,NvLnk_URLs) ) , VPara *vp; int oldlen; for ( 1=3=0, κιnfo->acnt, ++1 ) { if ( ιnfo->anchors[1] .done==0 ) { if ( 3"sel ) break, ) ) if ( ι==ιnfo->acnt ) xvt_scr_beep() ; else { VιewShowSelectιon(vιew, fo->anchors[1] .pnum, ιnfo->anchors[1] .offset, ιnfo->anchors[1) .pnum,ιnfo->anchors[1] .o set+mfo->anchors[1] .length) , vp = vιew->sel.start. ara; oldlen = vp->para->tlen; if ( 'VιewApplyLιnk(vιew,ιnfo->anchors[1] .urls[k] , "",NULL) ) { xvt_scr_beep() ; return; ) info->anchors[1] .done = ++mfo->dcnt; NvLnkUpdatelnfo nfo,ιnfo->auιchorsf1] .pnum,mfo->anchors[1] .offset, vp->para->tlen-oldlen) ; NvLnkFιllup(w) ; ) ) void XVT_CALLC0NV1 DoNaviL ks(struct cstr *rs, View 'view) { struct navilink 'info = buildnl(rs,view) ; AnySetStopButton(view, ULL) ; if I fo==NULL ) { navι_dm_post_error(Navιlιnk_BadParse/*"Could not parse navilink data"*/). navilink. c Tua Mar 7 17:51:44 1995 6 vιew->page->frozen = false; ) else if ( ιnfo->acnt==0 ) { navι__dm_post_warnιng(Navιlιnk_NoLιnk/*"No potential links were found"*/),- freenl (info) ; vιew->page->frozen = false, - 1 else { if ( ιnfo->bad 1 navι_dm_post_warnιng(Navιlιnk_Errors/*"Errors were found in the navilink input "*/1 ; if I navι_xvt_dlg_create_res(WD_MODELESS, NvLnk, EM_ALL, NvLnk_eh, (long) info )==NULL_WIN 1 { xvt_dm_post_error("Can' open dialog"),- freenl(info) ; vιew->page->frozen = false, } ) ViewSetCursor(view) ; ■tyladlg.c Mad Mar 22 14:42:14 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved */ ♦include "xvt.h" ♦include "NaviPres.h" ♦include "func.h" ♦include "style.h" ♦include "view.h" ♦include "doc.h" ♦include "xlocal.h" ♦include "chooser.h" void XVT_CALLC0NV1 DocPageHeaderChanged(Document *doc. Page *page, int type); void XVT_CALLC0NV1 DocRedrawDP(Document *doc, DocPart *dp) , mt fsys_sa_me_or_no_dιr(char *namel, char *name2), static int inlist PROTOTYPE((char **,char *)),- static int TSM_to_Index PROTOTYPE! (XVT_FONT_STYLE_MASK) ) , static XVT_FONT_STYLE_MASK Index_to_TSM PROTOTYPEI Imt)) , static void ImtList PROTOTYPE! (WINDOW,int,char **)), static void InitStyleList PROTOTYPE! (WINDOW, int) ) , static void Freestyle PROTOTYPE! (STYLE *)), static XVT_FNTID get_font PROTOTYPE! (char *,XVT_FONT_STYLE_MASK, long) ) , static void ιnιt_para PROTOTYPE! (struct p_εtyle *,XVT_FNTID,in , mt, in ,enum 3uεt_type,cha r *)); static void ιnιt_emph PROTOTYPE! (struct e_style *,XVT_FNTID,XVT_FONT_STYLE_MASK,char *)), static STYLE normalspam, STYLE *current= inormalspam, "defstyle = tnormalspam, *normalstyle= inormalspam, STYLE 'StyleHead(voιd) { return tnormalspam, ) /* These are the naunes in the style sheet, must be consistant accross langs */ static char *pnames_[] = { "Normal", "Headerl", "Header2", "Header3", "Header4", "Header5". "Header6", "BlockQuote" , "Pre", "Listing", "Address' , NULL ); static char *enames_[] = { "B" , "I", "U" , "TT" , "Citation", "Code", "Definition", "Emphasis", "KeyBoard", "Sample", "Strong', "Sub", "Sup", "Variable", "Anchor", "CachedAnchor" , "AnchorPoint" , NULL }, /* These are the names shown to the user, set in InitStyles */ static char *pnames[12], "enaunes[20] ; static char "snatnesI] = { "Normal", "Bold", "Italic", "Underline", "UnderDash", "Boldltalic" , "BoldUnder", "BoldDash", "ItalicUnder", "ItalicDash" , "BoldltalicUnder" , "BoldltalicDash" , "Subscript", "Superscript" , NULL ); static char *tιmes_font="times" , *courιer_font="courier", static mt inlist(char **lιst, char *na_me) { int l, for ( 1=0; lιst(ι) '=NULL; ++ι 1 if ( strcmpdist[I] ,naune)==0 1 return( I 1 , return( -1 ) ,- } static int TSM_to_Index(XVT_FONT_STYLE_MASK mask) { ♦define msk_match(msk.chk) ( ( (mskli(chk) 1==(chk) 1 f (msk_match(mask,XVT_FS_BOLD|XVT_FS_ITALIC|XVT_FS_USERl) ) return(11) , if (msk_match(mask,XVT_FS_BOLD|XVT_FS_ITALIC|XVT_FS_UNDERLINE) ) atyladlg.c Wad Mar 22 14 : 42 : 14 1995 2 return ( 10 ) ; i f (msk_match (mask, XVT_FS_ITALIC | XVT_FS_USERl ) ) return ( 9 ) ,- if (msk_match (mask, XVT_FS_ITALIC |XVT_FS_UNDERLINE) ) return ( 8 ) ; if (msk_match (mask, XVT_FS_BOLD | XVT_FS_USERl ) ) return ( 7 ) ; if (msk_match(mask,XVT_FS_BOLD|XVT_FS_UNDERLINE) ) return(6) ,- if (msk_match(mask,XVT_FS_BOLD|XVT_FS_ITALIC) ) return(5) ; if (msk_match(mask,XVT_FS_USERl) ) return(4) ; if (msk_match(mask,XVT_FS_UNDERLINE) ) return(3) ,- if (msk_match(mask,XVT_FS_ITALIC) ) return(2) ; if (msk_match(mask,XVT_FS_BOLD) ) return(1) ; return(0) ; ♦undef msk_match ) static XVT_FONT_STYLE_MASK Index_to_TSM(int index) { XVT_FONT_STYLE_MASK ret=XVT_FS_NONE; switch(index) { default: ret = XVT_FS_NONE; break; case 1: ret = XVT_FS_BOLD; break; case 2: ret = XVT_FS_ITALIC; break; case 3: ret = XVT_FS_UNDERLINE; break; case 4: ret = XVT_FS_USER1; break; case 5: ret = XVT_FS_BOLD| VT_FS_ITALIC; break; case 6- ret = XVT_FS_BOLD|XVT_FS_UNDERLINE; break; case 7: ret = XVT_FS_BOLD|XVT_FS_USER1; break; case 8: ret = XVT_FS_ITALIC|XVT_FS_UNDERLINE; break; case 9: ret = XVT_FS_ITALICjXVT_FS_USER1; break; case 10: ret = XVT_FS_BOLD|XVT_FS_ITALIC|XVT_FS_UNDERLINE; break; case 11: ret = XVT_FS_BOLD|XVT_FS_ITALIC|XvT_FS_USERl; break, case 12: ret = XVT_FS_USER2; break; case 13: ret = XVT_FS_USER3; break, ) return(ret) ,- ) static void FreeStyleContents(STYLE *stl) { int i; tor ( ι=0; ι< P_Max; ++i ) { if ( stl->paras[i] .fid '= NULL ) xvt_font_destroy( stl->paras[i] .fid ); if ( stl->paras[ι] .colour '= NULL ) myfree((char *) stl->paras[l] .colour ); stl->paras[ι] .fid = NULL; } for ( 1=0; ι< EM_Ma_x; ++ι ) ( if ( stl->emphs[ι] .fid '= NULL ) xvt_font_destroy( stl->emphs[ι] .fid ); •stl->emphs[i] .fid = NULL; if ( stl->emphs[i] .colour '= NULL ) myfree((char *) stl->emphs[i] .colour ); stl->emphs[l] .colour = NULL; atyledlg.c Wad Mar 22 14:42:14 1995 3 for ( ι=0, ι<Lιst_Repeat, ++ι ) { if ( stl->lιst_bullets[ι] .gιf_name'= NULL ) myfreet (char *) stl->lιst_bullets[l] gιf_name ), stl->lιst_bullets[l] .gιf_name = NULL, ) ) static void Freestyle(STYLE *stl) { FreeStyleContents(stl) , if ( stl'=tnormalspam ) { myfree(stl->name) , myfree( (char *)stl); ) ) static void Removes yle(STYLE *stl) { STYLE *p, Document "doc DocPart "dp, if ( stl'=NULL tt stl'=tnor_ι_alspam ) { for ( p= tnormalspam; p'=NULL ii p->nex '=stl, p = p->next ) if ( p'=NULL ) p->next = stl->next, PagesDeStyle(stl) , VιewsDeStyle(stl) , doc = DocLookupContaιnsFιle(stl->na_me) , if ( doc'=NULL ) { dp = LookupDocPar (doc, fsys_nametaιl(stl->name) 1 , if ( dp'=NULL ) { DocRemovePar (doc,dp,true) DocRedraw(doc) ; } } Freestyle(stl) , ) ) static XVT_FNTID get_font(char 'family, XVT_FONT_STYLE_MASK style long int size) { XVT_FNTID new, new = xvt_font_create() , xvt_font_set_fa_mιly(new,fatmily) , xvt_font_set_sιze(new,size) , xvt_font_set_style(new,style) , return(new) , } static void ιnιt_para(struct p_style 'para, XVT_FNTID fid, int in, int si, int il, enum 3u st_type 3 ust, char 'colour) { if ( para->fιd '= NULL ) xvt_font_destroy(para->fιd) , para->fιd = fid, para->ιndent = n, para->sub_mdent = si para->ιnιt_lead = l, para-> 3 ust = 3 ust, if ( para->colour '= NULL ) myfree( (char *)para->colour) , if ( colour '= NULL ) colour = copy(colour) , para->colour = colour, } ■tyladlg. c Wad Mar 22 14 : 42 : 14 1995 4 static void ιnιt_emph (struct e_style 'emph , XVT_FNTID fid, XVT_FONT_STYLE_MASK style , char • colour ) { if ( emph->fιd '= NULL ) xvt_font_destro (emph->fid) , emph->fid = fid, emph->style_ιt_ask = style; if ( emph->colour '= NULL ) myfree! (char *)emph->colour) ; if ( colour '= NULL ) colour = copy(colour1 , emph->colour = colour, ) void XVT_CALLCONVl DefaultStyle(STYLE *stl) { int l; char buf[60] , ιnι ___ara(istl->paras[P_Normal] ,get_font(tιmes_font,XVT_FS_NONE, 12L) ,0, 0,12,J_Left,NUL L), ιnιt_para(istl->paras[P_Hl] ,get_font(tιmes_font,XVT_FS_BOLD,24L) ,0,0,12,J_Center.NULL) ιnιt_para(istl->paras[P_H2] , et_font(tιmes_font,XVT_FS_BOLD,18L) , 0, 0,12,J_Left,NULL) , ιnιt_para(is l->paras[P_H3] ,get_font(tιmes_foπt,XVT_FS_NONE,18L) ,0,0,12,J_Left,NULL) , ιnιt_para(tstl->paras[P_H4] ,get_font(tιmeε_font, VT_FS_BOLD,14L) , 0,0,12,J_Lef .NULL) , ιnιt_para(tstl->paras[P_H5] ,get_fon (tιmes_font,XVT_FS_NONE,14L) ,0,0, 12,J_Lef ,NULL) , ιn t_para(istl->paras[P_H6] ,get_fon (tιmes_fon , VT_FS_NONE,12L) ,18,0,12,J_Left,NULL) , ιnιt_para(tstl->paras[P_Lιstιng] ,get_fon (courιer_font,XVT_FS_NONE, 10L) , 0,0, 12,J_Left, NULL) , ιnιt_para(istl->paraε[P_BlockQuote] ,get_font(tιmeε_font,XVT_FS_NONE,12L) ,24, 24.12,J_Le ft,NULL) ; mιt_para ( tstl ->paras [ P_Pre ] , get_fon (couπer_f ont , XVT_FS_NONE , 12L ) , 0 , 0 , 12 , J_Lef t . NULL ) ; ιnιt_para(tstl->paras[P_Address] ,get_fon (tιmeε_font,XVT_FS_ITALIC,12L) ,24,24, 12, _Lef t,NULL) ; ιnιt_emph(tstl->emphs[EM_B) ,NULL,XVT_FS_BOLD,NULL) , ιnιt_emph(tstl->emphs[EM_I] ,NULL,XVT_FΞ_ITALIC, ULL) , ιnιt_emph(istl->emphs[EM_U] ,NULL,XVT_FS_UNDERLINE,NULL) , ιnιt_emph(istl->emphs[EM_TT] ,get_font(courιer_fon ,XVT_FS_NONE,12L) ,XVT_FS_NONE, ULL) , ιnιt_emph(tstl->emphs[EM_Anchor] ,NULL,XVT_FS_ITALIC|XVT_FS_UNDERLINE,xvt__res_get_str(C ol_Blue,buf,sizeof (buf) 11 , /* there must be a better way to do this based upon background color... */ ιnι _emph(tstl->eιttphs[EM_CachedAnchor) ,NULL,XVT_FS_ITALIC|XVT_FS_USER1, "0 128 128") , ιmt_emph(tstl->emphs[EM_AnchorPoint) ,NULL,XVT_FS_ITALIC, "magenta" ) , ιnιt_emph(istl->emphs[EM_Clte] ,NULL,XVT_FS_ITALIC,NULL) ; mιt_emph(istl->emphs[EM_Code] ,get_font(courιer_font,XVT_FS_NONE,12L) ,XVT_FS._NONE, ULL ); ιnιt_eπιph<istl->emphs[EM_Def nιtιon] ,NULL,XVT_FS_BOLD,NULL) , ιnιt_emph(istl->emphs[EM_Em] ,NULL,XVT_FS_BOLD,NULL) , ιnιt_emph(istl->emphs[EM_KBD] ,get_font(courιer_font,XVT_FS_NONE,12L) ,XVT_FS_NONE, ULL) ιnιt_emph(istl->emphs[EM_Samp] ,get_font(courιer_font,XVT_FS_NONE,12L) ,XVT_FS_NONE, ULL ); ιnιt_emph(tstl->emphs[EM_Strong] ,NULL,XVT_FS_BOLD,xvt_reε_get_εtr(Col_Red,bu ,εizeof (b uf))); ιnιt_emph(tstl->emphs[EM_Sub] ,NULL,XVT_FS_USER2, UL ) , ιnιt_emph(istl->emphε[EM_Sup] ,NULL,XVT_FS_USER3,NULL) , ιnιt_emph(tstl->emphs[EM_Var] ,get_font(courιer_font,XVT_FS_NONE,12L) ,XVT_FS_NONE,NULL) for ( ι=0, ι<Lιεt_Repeat; ++ι ) stl->lιst_numε[ι]= N_Arab; stl->list_bullets[0] .bullet = B_FC, atyledlg.c Wad Mar 22 14:42:14 1995 stl->list_bullets[l] .bullet = B_OC stl->list_bullets[2] .bullet = B_FS stl->list_bullets[3] -bullet = B_OS stl->list_indent = 40; stl->list_sub = 40; stl->list_lead = 6; stl->intralist_lead = 6; stl->prehr_points = 9; stl->posthr_points = 9; /* No dialogue access */ stl->hr_gif = NULL; stl->modified = 1; } static char *default_style_name(char 'buffer) { char "name; strcpy(buffer, (name=userdir_file("defaul .stl") ) ) ; myfree(name) ; returntbuffer) ; ) void XVT_CALLC0NV1 InitStyles(char 'defstylena e) { char buffer[500] ; int i; static int style_rids[] = {Style_Norτnal, Style_Bold, Style_Italic, Style_Underline, Style_UnderDash, Style_BoldItalic, Style_BoldUnder, Style_BoldDash, Style_ItalicUnder, Style_ItalicDash, Style_BoldItalicUnder, Style_BoldItalicDash, Style_Subscript, Style_Superscript, NULL_RID }; static int para_rids[] = {Style_Normal, Style_Hl, Style_H2, Style_H3, Style_H4, Style_H5, Style_H6, Style_BlockQuote, Style_Pre, Style_Listing, Style_Address, NULL_RID }; static int emph_rids[] = {Style_Bold, Style_Italic, Style_Underline, Style_Fixed, Style_Citation, Style_Code, Style_Definition, Style_Emphasis, Style_Keyboard, Style_Saraple, Style_Strong, Style_Subscript, Style_Superscript, Style_Variable, Style_Anchor, Style_CachedAnchor, Style_AnchorPoint, NULL_RID }; for ( i=0; style_rids[i] .'»NULL_RID; ++i ) snames[i] = copy(xvt_res_get_str(style_rids[i] ,buffer,sizeof(buffer) ) ) ,- for ( i=0; para_rids[i] !=NULL_RID; ++i ) pna esfi] = copy(xvt_res_get_str(para_rids[i] .buffer,sizeof(buffer) ) ) ,- for ( i=0; emph_rids[i] !-NULL_RID; ++i ) enaunes[i] = copy(xvt_res_get_str(emph_rids[i] .buf er,sizeof(buffer) ) ) ; normalspam.name = copy("Normal") ; normalspam.cansave = 1; DefaultStyle(inormalspaun) ; if ( defstylename!=NULL ) { Readstyle(defstylename,NULL_WIN,NUL , ULL) ; defstyle = current; ) normalspam. odified = 0; ) void XVT_CALLCONVl TermStyles(void) { STYLE "cur, 'next; int i,- for ( i=0; snaunes[i] !=NULL; ++i ) myfree( snaunes[ij ) ; •tyladlg.c Wad Mar 22 14:42:14 1995 6 tor ( i=0; pnames [i] !=NULL,- ++i ) myfree ( pnames [i] ) ,- for ( i=0; enaunes [i) !-NULL; ++i ) myfree( enaunes [i] ),- for ( cur = tnormalspam; cur!=NULL; cur = next 1 { next = cur->next; ♦if 0 /* They want this after we change it rather than here */ if ( cur->modified tt cur->cansave 1 if ( navi_dm_pos _as (General_Save/*"Save" */ , Style_Discard/*"Discard"*/ ,NULL_R ID, Style_SaveS/*"Save style %.40s?"*/, cur->name 1 ==RESP_DEFAULT ) .( current = cur; SaveThisStyle ( ) ; ) ♦endif Freestyle(cur) ; } ♦if 0 /* They want this after we change it rather than here */ NPCrudRunDown( 1 ; ♦endif } void XVT_CALLC0NV1 StyleWasDeleted(STYLE *stl) { RemoveStyle(stl) ; ) static STYLE 'TempCopyStyle{char 'name, STYLE *stl) { STYLE 'new; int i=0; XVT_FNTID fid; char 'colour; new = (STYLE *) myalloc (sizeof (STYLE) ) ; 'new = *stl; new->name = copy(naune) ; new->next = NULL; for ( i=P_Normal; i<P_Max; ++i ) { if ((fid = new->paras[i] .fid) !=NULL ) xvt_font_copy(new->paras [i] .fid = xvt_font_create( ) , fid,XVT_FA_ALL) ; if ((colour = new->paras [i] .colour) !=NULL 1 new->paras[i] .colour = copy(new->paraε [i] .colour) ; ) for ( i=EM_B; i<EM_Max; ++i ) { if ((fid = new->emphs[i] .fid) ! -NULL ) xvt_font_copy(new->emphs [i] .fid = xvt_font_create( ) , fid,XVT_FA_ALL) ; if ((colour - new->emphs [i] .colour) !»NULL ) new->emphs [i] .colour = copy(new->eπphs [i] .colour) ; ) for ( i=0; i<List_Repeat; ++i ) { if ( new->list_bullets[i] .gif_name!=NULL ) new->list_bullets [i] .gif_naune = copy(new->list_bullets [i] .gif_name) ,- ) new->modified = 1; new->cansave = 1; return(new) ,- } static void InsertNewStyle (STYLE 'new, WINDOW w) { STYLE *stl; WINDOW Styles; int i«0; for ( stl= tnormalspam, i=l; stl->next! =NULL; stl = stl->next 1 ++i; •tyladlg.e Wad Mar 22 14 :42 : 14 1995 7 stl->next = new; if ( w!=NULL_WIN ) { xvt_lιst_ad (Styles = xvt_wιn_get_ctl (w,StlDLG_StyleNameε) , ι,new->name) ; xvt_lιst_set_sel(Styles,i,1) ; Style_Select(w) ; ) current = new; ) STYLE *CopyStyle(char 'name, STYLE *stl, WINDOW w) { STYLE "new; new = TempCopyStyle(name,stl) ,- InsertNewStyle(new,w) ,- return(new) ,- ) static long junk(WINDOW w, EVENT *e) { return 0; ) static int font atch(char 'sub, char *str) { int ch, chs; while ( *sub!='\0' ) { while ( (ch = *sub++)==' ' ) ; while ( (chs = *str++)==' ' ) ; if ( isupper(ch)) ch = tolower(ch); if ( lsupper(chs) ) chs = tolower(chs) ; if ( ch!=chs ) return( 0 ) ; ) return( 1 ) ,- ) static int fontinlchar 'sub, char *str) ( while ( *str!=' .0' ) { if ( fontmatch(sub,str) 1 return 1,- ++str; ) return 0; } static char 'LookForFon (char 'stdnaune, char 'request, char "families, int fcnt ) { if ( fontin(stdnaune,request) ) { for ( i=0; ι<fcnt; ++i ) if ( fontin(stdname, families[i] ) ) return( amilies[i] ) ; return( " " ) ; ) return( NULL ) ; ) static void FamilyCheck(XVT_FNTID fid,XVT_FONT_STYLE_MASK 'style) ( /* Check to make sure the font has a valid family on this system. Under */ /* uπix, if the family is bad xvt ignores the size and style info. So */ /* check to see if the family is going to be bad, and if so replace with */ /* a good one */ /* Also the different systems seem to have different names for the same */ atyladlg.c Wad Mar 22 14:42:14 1995 /* font. Try and deal with some simple cases */ static WINDOW 3unkwιn; char realna e[80] , mappedname[80] ; int tιme=0, helv=0, cour=0; char "str; εtatic char "fa_mιlιes; static int fcnt; if ( famιlιes==NULL ) { families = myalloc(lOO'sizeof(char *)), fcnt = xvt_fraap_get_famιlιes(NULL,families,100) , ) if ( 3unkwιn==NULL_WIN ) { RCT ret; ret.top = 0; rct.lef =0; re .bottom=l, rct.rιght=l, 3 unkwιn = xvt _wιn_create (W_ DOC , tret , "Junk" , 0 , TASK_WIN , WSF_INVISIBLE | WSF_NO_MENUBAR 0L, 3unk, 0L) ; ) xvt_font_get_fa_mιly(fid,realname,sizeof(realname) ) , xvt_font_map(fid,3urikwm) ; xvt_font_get_famιly_mapped( ιd, appedname,sizeof(mappedneune) ) , if ( ' fontin(realname, appedname) '=0 ) ( str = NULL, /* Look for the standard postscript fonts found in lazywriters */ if (( str=LookForFont(realname,realname,families, fcnt) ) •= NULL ScSc *str'='\0' ) { /" Oh goody, we found t (why didn't xvt?) */ ) else if (( str=LookForFont("Century Sch" ,realname,faunilies,fcnt))'= NULL ) ( /* New century Schoolbook */ time = 1; } else if ( ( str=LookForFont("Avant Garde" ,realname,families,fcnt))'= NULL 1 ( helv = 1 ) else if ( ( str=LookForFon ("Bookman' ,realname, families, fcnt11 '= NULL 1 { time = 1 } else if ( ( str=LookForFont("NHelvetica" ,realnaune,families,fcnt))'= NULL ) { helv = 1 } else if ( ( str=LookForFont("Helvetica" ,realname,families, fcnt) ) '= NULL 1 ( helv = 1 ) else if ( ( str=LookForFon ("Palatino" ,realname,families, fcnt))'= NULL ) ( } else if ( ( str=LookForFontI"times" ,realname, familieε,fcnt) 1 '= NULL ) { ) else if ( ( str=LookForFontI"Courier" ,realname,faunilies, fcnt) )'= NULL ) I cour = 1 ) else if (( str=LookForFont("Zapf Chancery" ,realname,faunilies, fcnt) )'= NULL ) ( italic = 1; /* Standard X scaleable fonts */ ) else if (I str=LookForFont("lucidatypewriter",realname, families,fcnt))'= NULL ) { cour = 1 ) else if ( ( str=LookForFontI"lucidabright" ,realnaune,families,fcnt) )'= NULL ) } else if ( ( str=LookForFont("luc da",realname, families, fcnt) ) '= NULL ) { helv = 1 } else if (( str=LookForFont("charter" ,realname,faunilies, fcn ))'= NULL 1 ( ) else if ( ( str=LookForFont("termina ".rea name, ami ies, cnt = NULL ) I cour = 1 /* Standard mac fonts */ } else if (( str=LookForFontI"Chicago" ,realnaune, faunilies, fcnt) ) '= NULL ) ( cour = 1; bold = 1, ■tyladlg.c Wad Mar 22 14:42:14 1995 9 ) else if ( ( str=LookForFont "Monaco",realname, families,fcnt) )'= NULL ) { cour = 1 else if ( ( str=LookForFont • Monaco".realnaune, amilies,fcnt) ) '= NULL ) { else if ( fontin("New York .realname) ) { time = 1 else if ( ( str=LookForFont "Monaco".realname,faunilies, cnt) )'= NULL ) { else if ( onti {"Geneva",realname { helv = 1 /* Standard PC fonts */ else if ( ( str=LookForFont "Ariel".realnaune,families, cnt) ) '= NULL ) { helv = 1 else if ( ( str=LookForFont "Impact Bold" .realnaune,families, cnt) )'= NULL ) { helv = 1 bold = 1 else if ( ( str=LookForFont "MS Sans Serif" .realnaune, amilies, cnt) ) '= NULL ) { helv = 1 else if { ( str=LookForFoπt "Book Rounded", ealname,families,fcnt))'= NULL ) { time = 1 else if ( { str=LookForFont "Book Antiqua", ealname,families,fcnt))'= NULL ) { time = 1 else if ( ( str=LookForFont "Footlight MT Light" .realname,families fcnt))'= NULL ) { time = 1, else if ( ( str=LookForFont "MS Linedraw" ,realnaune,families,fcnt) )'= NULL 1 { time = 1, else if ( ( str=LookForFont "MS Serif".realname,families,fcnt) ) '= NULL ) { time = 1, else if ( strmatchl"Roman" realnaune) ) { time = 1, else if ( ( str=LookForFont "Wide Latin",realname,families,fcnt) ) •= NULL ) { time = 1, /* Random common fonts */ else if ( str=LookForFont "Gothic".realname, families, fcnt) ) '= NULL ) { helv = 1 else if ( str=LookForFont "Bembo" ,realname, amilies, cnt))'= NULL ) { time ~~ 1 else if ( str=LookForFont 'Bodoni".realnaune,families,fcnt) ) '= NULL ) { time = 1 else if ( str=LookForFont "Caslon".realname,families fcnt))'= NULL ) { time = 1 else if ( str=LookForFont "Cheltenham",realname. faunilies,fcnt) )'= NULL ) ( time = 1 else if ( str * LookForFont ■ ChelthmlTC",realname,families, cnt) ) '= NULL ) { else if ( str * LookForFont 'Eurostyle",realname,families,fcnt) ) '= NULL ) { helv = 1, else if ( str * LookForFont "Future".realname,families, cnt) ) '= NULL ) { helv = 1, else if ( str=LookForFont "Galliard" ,realname,families,fcnt) ) '= NULL ) { else if ( str=LookForFont "Gararoond",realname,families,fcnt) )'= NULL ) { time = 1, else if ( str=LookForFont "Gill Sans" .realname, families,fcnt) ) ' * NULL ) { helv = 1, else if ( str * ookForFont "Goudy".realnaune,faunilies,fcnt)) '= NULL ) { time = 1, else if ( str»LookForFont "Grotesque",realname,families, cnt) )'= NULL ) { time = 1, else if ( str=LookForFont "Melior".realname, families,fcnt) ) '= NULL ) { time = 1, else if ( str=LoσkForFont "Optima" .realname,families,fcnt) )'= NULL ) { helv = 1, else if ( str=LookForFont "Univers".realname, amilies,fcnt) ) '= NULL ) { helv = 1, atyladlg.c Wad Mar 22 14 :42 : 14 1995 10 ) if I str ! *NULL tele *str ' = ' \0 ' ) { xvt_font_set_famιly( fιd, str) ; xvt_font_get_famιly ( fιd, realname, sizeof ( realname) ) , xvt_font_map ( fιd, 3unkwιn) ; xvt_font_get_family_map ed ( fid, appedname , sizeof (mappedname) ) , =0 1 { xvt_font_set_fa_mιly(fιd,str) , xvt_font_get_family(fid,realname,sizeof (realname) ) , xvt_font_map(fιd,3unkwm) ; xvt_font_get_famιly_mapped(fιd,mappedname,sizeof (mappedname) ) ) if ( bold ) 'style |= XVT_FS_BOLD; If ( italic ) 'style |= XVT_FS_ITALIC; } STYLE * XVT_CALLC0NV1 ReadStyle(char 'name, WINDOW w, STYLE 'new, char *refered_by) I char buffer[300] , famιly[300], colour[100], "pt, mt l, ok=l, len; FILE *ιn; long size; XVT_FONT_STYLE_MASK style, static char 'nestnames[)={"1", "2" , "3" , "4",NULL} , int 3ust, num, bullet. if ( fsys_ιs_url(naune) ) { if ( new==NULL ) new = CopyStyle(name,tnormalspam,w) ,- StyleRead (new,NULL,refered_by) ; return(new), /* Return a copy of the default for now */ ) if (dn = fopen(naune. "r") )==NULL ) ( navι_dm_post_error(Style_CantRead/*"Cannot open %s for reading a style"*/, name ) return(NULL) ; ) if (fgets(buffer,sizeof(buffer)-1,ιn)=«NULL || (strcmp(buffer, "STYLESn") '=0 it strcmp(buffer, "STYLE\r\n") '=0) ) { nav _dn_post_error(Style_NotStyle/*"%s does not contain a style"*/, naune ), return(NULL) ; } if ( new==NULL ) new = CopyStyle(naune,tnor a1spam,w) ,- while ( fgets(bu fer,sizeof(buffer)-1, in) '=NULL ) { if (( pt = strchr(buffer, ':')) '=NULL ) { *pt='\0'; if (d = inlist(pnames_,buffer) ) '= -1 ) { size = 12; style = XVT_FS_NONE; strcpy(family,tιmeε_fon ) , colour[0]='\0' ; if ( sscanf(pt+1, " family, tsize, tstyle, tnew->paraε[I] .inden , tnew->paras[lJ .sub_ιndent, tnew->paras[i] .ιmt_lead, t3ust. styledlg.c Wad Mar 22 14:42:14 1995 11 colour )<7 /* Allow colour to be missing */ ok = 0, if ( sιze==0 ) sιze=12, /* I've seen this happen, don' know why */ new->paras[I] 3 ust = 3ust, if ( strcmp(colour, "-")==0 ) colour[0)='\0' ; xvt_font_set_famιly(new->paras[i] .fid, family) , FamιlyCheck(new->paras[ι] .fid.istyle) , xvt_font_set_sιze(new->paras[iJ .fid,size) , xvt_font_set_style(new->paras[ι] .fid,style) , if ( new-> aras[I] colour'=NULL ) { myfree( (char *)new->paras[ι] .colour), new->paras[I] colour = NULL, ) if ( colour(O) '='\0' ) new->paraε[ι] .colours copy(colour) , ) else if (d = inlist(enames_,buffer) ) '= -1 ) { size = 12, style = XVT_FS_NONE, strcpy(family,couπer_fon ) , if (den = sscanf(pt+1, " Ox%lx \"%["\"]\" \"%["\"]\" %ld 0x%lx", Obsolete convention */ inew->emphs[l] style_ιtιask, colour, family, isize, tstyle))==0 ) if ((len = sscanf(pt+1, ' \"%[ ]\" 0x%lx", colour, tstyle ))==2 ) /* All happy and nice */ else if ((len = sscanf (pt+1, " \ " % r \ " i \ " \ - % r \ " ] \ " %ld 0x%lx", colour, family, tsize tstyle) )==0 ) ok = 0, else { new->emphs[l] .style_mask = style ++len, } } if ( sιze==0 ) sιze=12, /* Don't know why this happens, font dig returned sιze=0 once */ if ( strcmplcolour, " )==0 ) colour(0]='\0' , if ( new->emphs[l] .colour'=NULL ) { myfree((char *)new->emphs[l] colour), new->emphs[l] .colour = NULL ) f ( colour[0] '='\0' ) new->emphs[l] colour= cσpy(colour) , if ( len<=2 ) { if ( new->emphs[1] fιd'=NULL ) xvt_font_destro (new->emphs[I] fid) , new->emphs[l] .fid = NULL, } else if ( len'=5 ) ok = 0, else { if ( new->emphs [i j . fιd"NULL ) new->emphs [i ] . f id = xvt_f ont_create ( ) , xvt_font_set_famιly(new->emphs [ i ] fid, family) , FaunιlyCheck (new->emphs [ 1] . fid, tstyle) , xvt_font_set_sιze (new->emphs [l ] fid, size) , xvt_f ont_set_style (new->emphs [i ] fid, style) , ) ) else if ( pmatch ! "example" . buffer) ) { /* Obsolete , ignore gracefully * / ) else if ( = inlis (nestnames , buf fer ) ) ' = -1 1 ( if ( new->lιst_bullets [ι ) . gιf_naune ' =NULL 1 { myfree Uchar * )new->lιst_bullets [ ij gιf_name) , new->lιst_bullets [l] .gιf_name = NULL, ) if ( den = sscanf (pt + 1 , "%d %d %s" , tnum, tbullet , family ) ) == 3 1 { new->lιst_bullets [l ] ,gιf_naune = copy ( family) , styledlg.c Wad Mar 22 14:42:14 1995 12 } else if ( len!=2 ) ok = 0; new->list_nums[i)=nuιτι; new->list_bullets[i) .bullet-bullet; } else if (strcmplbuffer, "Lists")==0 ) { if ( sscanf(pt+1, "%d %d %d d", inew->list_indent, tnβw->list_sub, inew->list_lead, inew->intralist_lead ) ! = 4 ) ok » 0; } else if istrcmplbuffer, "HR")==0 ) { if ( new->hr_gif_name!=NULL ) { yfree! Ichar *)new->hr_gif_name) ,- new->hr_gif_name = NULL; new->hr_gif = NULL; ) if ( en = sεcanf(pt+1, "%hd %hd %s", inew->prehr_points, tnew->posthr_points, family ))== 3 ) { new->hr_gif_naune = copy(family) ,- ) else if ( len!=2 ) ok = 0; } else ok = 0; ) > fclose(in) ; if ( !ok ) navi_dm_poεt_warning(Style_Invalid/*"%s iε in an invalid format, it may be odd"*/, name ) ; return(new) ,- } STYLE * XVT_CALLC0NV1 FindStyle(char 'name, char *cur, char 'base) { char buffer[800], anchor[40]; STYLE 'stl; URLTrans(name,cur,base,buffer.anchor,sizeof(bu fer) .sizeof(anchor) ) ; for ( stl= inormalspaun; stl!=NULL tt fsys_urlc___p(stl->naune,buffer) !=0; stl=stl->next ) if ( stl!=NULL ) return( stl ) ,- return! ReadStyletbuffer,NULL_WIN,NULL,cur) ) ; ) STYLE * XVT_CALLCONVl LookupStyle(char 'name, char *cur, char 'base) { char buffer[800], anchor(40],- STYLE *stl; URLTrans(name,cur,base,buffer.anchor.sizeof(buffer) .sizeof(anchor) ) ; for ( stl= inormalspam; stl!=NULL ti fsys_urlcmp(stl->naune,buffer) !=0; stl=stl->next 1 return( stl ) ; ) int XVT_CALLCONVl DoSaveStyle(struct cstr *ws, char 'name, STYLE *stl, int saveimages, str uct document *doc) { char buffer[500] , buffer2 [500] ; int i.ret; if ( saveimages ) { ■ for ( i=0; i<List_Repeat; ++i ) ( if ( stl->list_bullets[i] . if_name!=NULL it GenerateSaveName(stl->list_bullets[i] .gif_name,stl->name, name,saveimages,buffer,sizeof(buffer) ,doc) ) { URLTranε(stl->list_bullets[i] .gif_name,stl->name,NULL,buffer2.buffer2+499, •tylβdlg.c Wad Mar 22 14:42:14 1995 13 sizeo (buffer2) ,1) , if (( ret = CopyURLToFile(buffer2,buffer,doc) )<=0 ) { return( ret ) , ) myfree( stl->lιst_bullets[l] .gιf_name ); stl->lιst_bullets[ι] .gιf_naune = copy(buffer) ; ) ) if ( stl->hr_gιf_na_me it GenerateSaveName(stl->hr_gιf_naune,stl->naune, name,saveimages,buffer,sizeof(buffer) ,doc)<=0 ) { URLTrans(stl->hr_gιf_name,stl->name, ULL,buf er2,buffer2+499,sizeof(buffer2) ,1 ); if (( ret = CopyURLToFile(bu fer2,buffer. oc) )<=0 ) { return( ret ) ; } myfree! stl->hr_g f_ήame ), stl->hr_gιf_name = copy(buffer) , ) } WsPutStrlws, "STYLE.n") , for ( ι=0, ι<P_Max; ++ι ) ( xvt_font_get_famιly(stl->paras[l] .fid,buffer, (long) sizeof(buf er) ) , WsPrintlws, "%s: \"%s\" %ld 0x%lx %d %d *d d ", pnameε_[ι], buffer, xvt_font_get_sιze(stl->paras[ι] .fid) , xvt_font_get_style(stl->paras[l] .fid) , stl->paras[IJ .indent, stl->paras[l] .sub_ιndent, stl->paras[i] .ιnιt_lead, stl->paras[ι] oust ) ,- if ( stl->paras[ι] .colour==NULL || stl->paras[l] .colour[0J=='\0' ) WsPutStrlws, "\"-\"\n" ); else WsPrιnt(wε, "\*%s\"\n", stl->paras[i] .colour ), ) WsPutClws, ' \n' ) ; for ( ι=0, ι<EM_Max, ++ι ) { WsPrin (ws, "%s ", enames_[I] ) ; if ( stl->emphs[l] .colour==NULL || stl->emphs[I] .colour(0)=='\0' ) WsPrιnt(ws, "\"-\" " ); else WsPrintlws, "\"%s\" ", stl->emphs[I] .colour ), if ( stl->emphs[ι] .fιd'=NULL ) { xvt_font_get_famιly(stl->emphs[ι] .fid.buffer, (long) sizeof(buffer) 1 , WsPrintlws, "\"%s\" %ld Ox%lx", buffer, xvt_font_get_sιze(stl->emphs[l] .fid) , xvt_font_get_style(stl->emphs[1] .fid)) ; } else WsPrintlws, "Ox%lx", stl->emphs[ ] .style_mask) , WsPutClws, '\n') , ) WsPutClws, '\n' ) , for ( ι=0; ι<Lιst_Repeat; ++l ) { WsPrintfws, "%d: %d %d", i+l, stl->lιst_nums[I] , stl->ιιst_bullets[ι] .bullet ), if ( stl->lιst_bullets[ι] .g f_name'=NULL ) WsPr ttws, " %ε", stl->l st_bullets[I] .gιf_name ), WsPutClws, '\n' ) ; ) WsPrmt) ws, "Lists- %d %d %d %d\n", stl->lιst_ιndent, stl->lιst_sub, stl->lιst_lead, stl->ιntralιst_lead) ; WsPrmt! ws,"HR: %d %d", stl->prehr_pomts, stl->posthr_poιnts ) ; if ( stl->hr_gιf_naune' * NULL ) WsPrintlws, " s", stl->hr_gιf_name ), WsPutClws, '\n' ) ; stl->modι ied = 0, return( 1 ) , atyladlg.c Wad Mar 22 14 :42 : 14 1995 14 } int XVT__CALLC0NV1 SaveThisStyle(void) { char 'naune; char buffer[500] ; naune = current->name; if ( na_me==NULL || *neune=='\0' || strcmp(name, ">> Default <<")==0 ) { naune = default_style_name(buffer) ,- } return(SaveStyle(current,name,1,NULL,NULL) ) ,- ) void XVT_CALLCONVl Style_Select(WINDOW w) { WINDOW Styles; STYLE *stl; int sel=0, i; sel = xvt_list_get_sel_index(Styles = xvt_win_get_ctl(w,StlDLG__StyleNaunes) 1 ; for ( stl= inormalspaun, i=0; stl!=NULL tt i!=sel; stl=stl->next, ++i 1 ; if ( stl!=NULL ) { current = stl; } xvt_ctl_set_checked(xvt_win_get_ctl(w, StlDLG_Def) ,current==defstyle) ; xvt_vobj_set_enabled(xvt_win_get_ctl(w, StlDLG_Cha_nge) .current!=normalstyle) , ) void XVT_CALLC0NV1 Style_Change(WINDOW w) { STYLE 'new. Old = current; new = TempCopyStyle(current->naune,current) ; current = new; if ( !navi_xvt_dlg_create_res(WD_M0DAL, CStl, EM_ALL, CStl_eh, w) ) { xvt_dm_post_error("Can't open dialog"); new->canceled = true; ) if ( new---canceled ) { Freestyle(new) ; current = old; } else { FreeStyleContents(old) ; myfree( old->name 1; Old = 'new; myfree(new) ; current = old; if ( curren ->tempmod ) { SaveThisStyle() ; ) ) ) void XVT_CALLC0NV1 StyleDef(WINDOW w) { if ( xvt_ctl_is_checked(xvt_win_get_ctl(w, StlDLG_Def) ) 1 { defstyle = current; /* Set Default */ PrefsSetChanged() ; } else if ( defstyle != inormalspaun ) { defstyle = tnormalspam; PrefsSetChanged() ; } else { xvt_ctl_set_checked(xvt_win_get_ctl(w, StlDLG_Def) ,true) ,- ) ) void XVT_CALLC0NV1 Style_Fillup(WINDOW w) { STYLE *stl; ■tyladlg.c Wad Mar 22 14 :42 :14 1995 15 for ( stl= inormalspam; stl ! * NULL; stl=stl->next ) stl->ternpmod = false ; InitStyleList I w, StlDLG_StyleNames ) ; xvt_ctl_set_checked(xvt_wm_get_ctl (w, StlDLG_Def ) , current==def style) ,- xvt_vob3_set_enabled(xvt_wιn_get_ctl (w, StlDLG_Change) . curren ! =normalstyle) ; ) void XVT_CALLC0NV1 NStyle_def name (WINDOW w, char 'name , mt strip) { char buffer [1000] ; char *pt; char nametail [60] , num[10) ; int cnt=0, offset = -1 ; if ( i strip ) fsys_buιld_neune (name, "miniweb. stl " . buffer , sizeof (buf fer) ) ,- else { strcpy (buf fer , naune) ; pt = fsys_naunetail (buf fer) ; if ( ( pt = strrchr (pt , ' . ' ) ) ! =_NULL ) { strcpy (pt , " . stl " ) ; } else strcat (buffer , " . stl " ) ,- ) while ( LookupStyle tbu fer, " " . NULL) ! =NULL | | ( ! fsys_ιs_url (buf fer) ti f sys_exιsts (buf fer ) ) ) { /* If the name is in use, try something else * / strcpy{naunetail , fsys_naunetail (buffer) ) ; sprintf (num, "%d" , cnt++ ) ,- i f ( offset == -1 ) ( if ( strchr (naunetail , ' . ' ) ==NULL ) offset = 8 ; else offset = strchr(nametail, ' . ' )-nametail; } if ( offset+strlen(num)>8 ) ( /* Damn fool short file names */ offset = 8-strlen(num) ; strcpy(nametail+offset,num) ,- ) else strcpy(nametail+offset,num) ; strcat(nametail, " .stl"} ; strcpyIfsys_nametaιl(bu fer) .nametail) ; ) xvt_vob3_set_title(xvt_wιn_get_ctl (w,NStlDLG_Name) .buffer) ,- void XVT_CALLC0NV1 NStyle_NameChange(WINDOW w) { char buffer[100] ; WINDOW edit = xvt_wιn_get_ctl(w,NStlDLG_Name) ; xvt__vob3_get_title(edιt, buffer.sizeof(buf er) ) ; xvt_vob3_set_enabled(xvt_wιn_get_ctl (w,DLG_0K) , buffer[0] '='\0' ) ; ) int XVT_CALLC0NV1 StyleBrowsed(void "ctx, char "url, struct chooserinfo *3unk) { WINDOW w = (WINDOW) Ctx; STYLE "stl, "new; for ( stl= inormalspam; stl!=NULL; stl=sti->next ) ( if ( fsys_urlcmp(stl->name,url)==0 ) { navι_dm_post_error(Style_Loaded/""Style %ε already loaded"*/, url ), return false; atyladlg.c Wad Mar 22 14 :42 : 14 1995 16 ) ) new = ReadStyle(url,w,NULL,NULL) : return true; ) void XVT_CALLCONVl Style_Open(WINDOW w) { char buffer[400] ; buffer[0]='\0'; Chooselt( (void *) w,Style_Local/*"Style file to open..."*/, buffer, sizeof(buffer) , CH00SER_STYLE, StyleBrowsed); ) void XVT_CALLC0NV1 NStyle_Init(WINDOW w) { WINDOW SW = xvt_vobj_get_dao_a(w) ,- View 'view; DocView *dv; view = (View *) xvt_vobj_get_data(SW) ,- if ( view==NULL ) / • Do Nothing */; else if ( vιew->tag == TAG_VIEW ) { NStyle_defname(w,view->page->url,true) ; ) else ( dv = (DocView *) view; NStyle_defname(w,dv->doc->naune, false) ; ) NStyle_NauneChange(w) ; navι_set_dlg_focus_tf(w,NStlDLG_Name) ; ) mt XVT_CALLC0NV1 NStyle_0k(WINDOW w) { char buf[1024] ; STYLE *stl; char *pt; STYLE 'new; Document *doc; long data; if ( xvt_vobj_get_title(xvt_win_get_ctl (w,NStlDLG_Naune) ,buf.εizeof(buf) )==NULL ) return(0) ; if ( buf[0]-='\0' 1 return(0) ,- if ( ( pt = strrchr(buf,'.')) !=NULL ) { strcpy(pt, " .stl") ; } else strcat(buf, " .stl") ; for ( stl= tnormalspam; stl!-NULL; stl=stl->next 1 { if I fsys_urlcmp(stl->name,buf)=«0 ) { navι_dm_post_error|Style_Duplicate/*"Duplicate style name s"*/, buf ) ,- xvt_vobj_set_title(xvt_wm_get_ctl(w,NStlDLG_Name) ,buf) ,- return( 0 ) ; ) ) new = TempCopyStyle(buf.current) ; data = xvt_vobj_get_data(w) ; xvt_vσbj_destroy(w) ,- new->tempmod = true; current = new; if ( !navi_xvt_dlg_create_res(WD_MODAL, CStl, EM_ALL, CStl_eh, data)) { xvt_dm_post_error("Can't open dialog"); new---canceled = true; ) •tyladlg.c Wad Mar 22 14:42:14 1995 17 if ( new->canceled ) { Freestyle(new) ; current = stl, } else { SaveThisStyle() ,- InsertNewStyle(new,data) ,- if ((doc = DocFromFιleneune(new->name,NULL) ) '=NULL ) ( DocInsertPart(doc, sys_nametaιl(new->naune) ,NULL) ; DocGraphNew(doc) ; DocDrawNew(doc) ; DocSetDιrty(doc) ; ) } return 1,- ) /* Either we changed the style of the current view, or we updated a style */ /* in any case remetric/redraw all affected windows */ void XVT_CALLC0NV1 ViewStyleSet(WINDOW w) { View "view = (View *) xvt_vob 3 _get_data(w) ; DocView *dv; Document *doc; WINDOW 'WindLiSt; int wen , l; STYLE *old = NULL; if ( vιew'=NULL tt vιew->tag==TAG_VIEW ) ( old = vιew->sheet; if ( vιew->page->sheet'=current 1 { myfree(view->page->style) , if ( current==normalstyle ) vιew->page->style = NULL; else if ( fsys_saune_or_no_dιr(current->name, ιew->page->url) 1 vιew->page->style = copy(fsys_nametaιl(current->name) ) ; else vιew->page->style = copy(current->name) , vιew->page->sheet = current; vιew->sheet = current; PageSetChanged(vιew->page,true) , VιewStdMsg(vιew) , if ( vιew->page->doc'=NULL ) ( DocPageHeaderChanged(view->page->doc, iew->page,u_style) , DocDrawNew(vιew->page->doc) ; ) } } else if ( vιew'=NULL ) { dv = (DocView *) view; doc = dv->doc; myfree(doc->style) ; if ( current -= tnormalspam ) « doc->style = NULL; else { char buffer[500] ; fsys_buιld_name(doc->name,fsys_naunetaιl(current-:-naune) .buffer, sizeof(buffer) ) ; if ( fsys_urlcmp(current->naune,bu fer) '=0 ) SaveStyle(current,buffer,1,doc,NULL) ; doc->style = copy(buf er) ; DocAddPageName(doc,buffer,-1,-1) ; ) doc->dιrty = true; styledlg.c Wad Mar 22 14:42:14 1995 18 WindList = WιndowHead(twcnt) ; for ( ι=0, Kwcnt, ++ι ) { vs = (View *) xvt_vob3_get_data(WιndLιst[i] ) , if ( vs->sheet->tempmod || (vs==vιew ti current'=old) ) ( ViewMetrics(vs) ; VιewRedraw(vs) ,- ) ) current->tempmod = false; } /* We 3 ust got back am image for a style gif, remetric/redraw all affected win*/ void XVT_CALLCONVl StyleRefresh(STYLE 'stl) { WINDOW 'WindList, mt went, l. View *vs; WindList = WindowHead(twent) ; for ( ι=0; Kwcnt; ++ι ) ( vs = (View *) xvt_vob3_get_data(WindList[i] 1 ; if ( vs->sheet==stl ) { ViewMetrics(vs) , if ( vs->sel.start.none 1 { vs->care .pmapped = true; vs->caret.mapped = false, ViewPlaceCaret(vs) ; ) else ( vs->sel.start.pmapped = true, vs->sel εtart.mapped = false, vs->sel.end. mapped = true, vs->sel.end.mapped = false, ViewMapPosition(vs,ivs->sel.start) ; VιewMapPoειt on(vs,tvs->sel end), ) VιewRedraw(vs) ; ) ) } int ImagelnStyle(STYLE *stl. Image 'image) { int l , if ( ιmage==stl->hr_gιf ) return( true ) , for ( 1=0, ι<Lιst_Repeat; ++ι 1 if ( ιmage==stl->lιεt_bulletε[i] .image ) return( true 1 ; return( false ) ,- ) /* Routines for Edit Style dialogue */ #defιne SEL_PARA 0 •define SEL_EMPH 1 •define SEL_LIST 2 •define SEL_HR 3 •define SEL.ORDERED 0 void XVT_CALLC0NV1 CStyleDismiss(WINDOW w) { if ( xvt_vob3_get_data(xvt_wιn_get_ctl(w,CStl_Color) )==0 ) /* It often doesn't lose focus under X so we need to check ourselves */ CStyleColourCheck(w) ; if ( xvt_vob3_get_data(xvt_wιn_get_ctl(w,CStl_Color) )==1 ) ( /* Bad color */ styledlg.c Wad Mar 22 14:42:14 1995 19 xvt_ctl_set_text_sel (xvt_wιn_get_ctl (w, CStl__Color ) , 0 , SHRT_MAX) ; xvt_vob3_set_data (xvt_wιn_get_ctl (w,CStl_Color ) , -ID , navι_set_dlg_focus_tf (w, CStl_Color) , return; ) xvt_vob 3 _destroy(w) ; } void XVT_CALLCONVl CStyleCancel(WINDOW w) { xvt_vob3_destroy(w) ; current->canceled = true, ) void XVT_CALLCONVl CStyleColourCheck(WINDOW w) { char buffer[80] , xvt_vob3_get_tιtle(xvt_wm_get_ctl(w,CStl_Color) .buffer,sizeof(buffer) ) , xvt_vob3_set_data(xvt_wm_get_ctl (w,CStl_Color) ,0L) ; /* No Errors */ if ( buffer[0]=='\0' 1 return, if ( ColourFName(buffer,true)==-l ) ( navι_dm_post_err " or(Style_BadColor/*"Bad color %s"*/, buffer), xvt_vob3_set_data(xvt_wιn_get_ctl(w,CStl_Color) ,IL) , } ) vo d XVT_CALLCONVl CStyleNum(WINDOW w, int cid) { char buffer[80], *pt; long val, mt sel, style_type, extern long strtoK); xvt_vob3_get_tιtle(xvt_wιn_get_ctl(w,cid) .bu fer,sizeof{buffer) ) , val = strtol (buffer.ipt, 10) . style_type = xvt_lιst_get_sel_ιndex(xvt_wm_get_ctl(w,CStl_Style) ) , sel = xvt_l st_get_sel_ιndex(xvt_wm_get_ctl(w,CStl_Mβ3or) ) , if ( • pf-' .O' ) { xvt_dm_post_message("Bad number" ) , *pt = '\0' , xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w,cιd) .buffer) } else if ( style_type==SEL_LIST ) ( if ( cιd==CStl_Fιrst ) current->lιst_ιndent = val, else if ( cιd==CStl_Subs ) current->lιst_sub = val; else if ( cιd==CStl_Lead ) current->lιst_lead = val; else if { cιd==CStl_Wιthιn ) current->lιst_lead = val, else xvt_scr_beep( ) ; } else if ( style_type==SEL_HR ) { current->prehr_poιnts = val, ) else if ( cιd==CStl_Fιrst ) current->paras[sel] .indent = val, else if ( cιd==CStl_Subs ) current->paras[sel] .sub_ιndent = val; else if ( cιd==CStl_Lead ) current->paras[sel] .mιt_lead = val, else xvt_scr_beep() , current->tempmod = 1, current->modιfied = 1, ■tyladlg.c Wad Mar 22 14:42:14 1995 20 void XVT_CALLC0NV1 CStyleText(WINDOW w, int cid) { char buffer[80], *bpt, *pt, **ppt, xvt_vob3_get_tιtle(xvt_wm_get_ctl(w,cid) ,buffer,sizeof(buffer) ) , sel = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Ma3or) ) ; bpt = buffer+strlen(buffer)-1; while ( navι_ιsspace(*bpt) ) • bpt-- = '\0'; bpt = buffer, while ( navι_ιsspace(*bpt) ) ++bpt; if ( cιd==CStl_Color ) { if ( xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Style) 1==SEL_EMPH 1 ppt = tcurrent->emphs[sel] .colour, else * ppt = tcurrent->paras[sel] .colour, •if 0 ) else if ( cιd==CStl_GIFname ) { sel2 = Nestmg(w) , ppt = icurrent->lιst_bullets[sel2] .gιf_name, ) else if ( cιd==CStl_HRGιf 1 { ppt = tcurrent->hr_gιf_name, current->hr_gιf = NULL, •endif ) else { xvt_scr_beep(1 , return; ) pt = *ppt, if ( pt==NULL it buffer[0]=='\0' ) /' Do Nothing */, else if ( buffer[0]«='\0' ) { myfree( (char *)pt) ; "ppt = NULL; ) else if ( pt==NULL ) "ppt = copy(buffer) , else if ( strlenlbuffer)<=strlen(pt) ) strcpy(pt,buffer) , else { myfree( (char *)pt), "ppt = copy(buffer) , ) current->tempmod = 1, current->modιfied = 1; ) void XVT_CALLCONVl CStyleJust(WINDOW w) { mt sel = xvt_l st_get_sel_mdex(xvt_wιn_get_ctl(w,CStl_Ma 3 or) 1 , current->paras[sel] ust = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl (w,CStl_Alιgn) 1 , current->tempmod = 1, curren ->modιf ed = 1; ) void XVT_CALLCONVl CStyleBulletOrNum(WINDOW w) { mt nesting = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Nested) 1 , int sel = xvt_lιst_get_sel_ιndex(xvt_wm_get_ctl (w,CStl_Ma3or1 ) , if ( sel==SEL_ORDERED ) { current->lιst_nums[nesting] = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl (w,CStl_Num) 1 , ) else { current->lιst_bullets [nesting] . bullet = styledlg.c Wad Mar 22 14 :42 :14 1995 21 xvt_lιst_get_sel_ιndex (xvt_wιn_get_ctl (w,CStl_Num) ) ; } current->tempmod = 1; curren ->modιfied = 1, ) static void XVT_CALLCONVl CStyleShowFont(WINDOW w, XVT_FNTID fid, XVT_FONT_STYLE_MASK mask ) { char buffer[200] ; if ( fid==NULL ) xvt_list_get_el (xvt_wιn_get_ctl(w,CStl_Emph) ,TSM_to_Index(mask) , buffer.sizeof(buffer) ) ,- else { xvt_font_get_famιly(fid,buffer,sizeof(buffer) ) ; strcat(buffer, "-") , xvt_lιst_get_elt(xvt_wm_get_ctl (w,CStl_Emph) ,TSM_to_lndex(mask) , buffer+strlen(buffer) .sizeof(buffer)-strlen(buffer) ) ,- if ( xvt_font_get_sιze(fιd)==0 ) xvt_font_set_sιze(fid,12) ; /* don't know how this happens, but it has "/ sprintf(buffer+strlen(buffer) , " %d" , xvt_font_get_sιze(fid) ) ; } xvt_vob3_set_tιtle(xvt_wm_get_ctl(w,CStl_DescText) .buffer) , } void XVT_CALLC0NV1 CStyleTypeStyle(WINDOW w) { t sel; XVT_FNTID fid; sel = xvt_lιst_get_sel_ ndex(xvt_wm_get_ctl(w,CStl_Ma3or) ) , curren ->emphs[sel] .style_mask = Index_to_TSM( xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl (w,CStl_Emph) ) ) ; if (( fid = current->emphs[sel] .fid) !=NULL ) xvt_font_set_εtyle(fid,current->emphε[sel] .style_maεk) , current->tempmod = 1; current->modιfied = 1, CStyleShowFont(w,current->emphs[sel] .fid,current->emphs[εel] .style_mask) , ) void XVT_CALLC0NV1 CStyleSelectFont(WINDOW w) { int sel, created=0; XVT_FNTID fιd=NULL; t inemph = 0; char buffer[80] ; View "view = (View *) xvt_vob 3 _get_data(w) ; sel = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Ma 3 or) ) ; if ( xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Style) 1==SEL_PARA ) { fid = current->paras[sel] .fid, ) else { if (( fid = current->emphs[sel] .fιd)==NULL ) { fid = current->emphs[sel] .fid = xvt_font_create(1 ; created = 1; xvt_vob3_set_vιsιble(xvt_wm_get_ctl(w,CStl_DelFont) ,1) ; } inemph = 1; ) if ( fιd'=NULL ) if I xvt_dm_post_font_sel(NULL_WIN, fid, NULL, 0L) ) { current->tempmod = 1; current->modι ied = 1; if ( inemph ) { styledlg.c Wad Mar 22 14:42:14 1995 22 curren ->emphs[sel] .style_mask = xvt_font_get_style(fid) , xvt_lιst_set_sel(xvt_wιn_get_ctl (w,CStl_Emph) , TSM_to_Index(current->emphs[sel] .style_mask) .true) , ) xvt_font_get_famιly(fid,buffer,sizeof(buffer) ) , if ( 'current->fontwarned tt strmatchtbuffer,tιmes_font) '=0 ti strmatch(buffer,courιer_font) '=0 it strmatch(buffer, "helvetica") '=0 ) { xvt_dm_post_warnιng("This font may not be portable"); current->fontwarned = true; ) } el Stl_DelFont) ,0) , ) if ( inemph ) CStyleShowFont(w,current->emphs[sel] .fid,current->emphε[εel) .εtyle_mask) , else CStyleShowFont(w,current->paras[sel] .fιd,0L) , ) void XVT_CALLC0NV1 CStyleRemoveFon (WINDOW w) ( int sel, sel = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl (w,CStl_Ma3or) ) , if (current->emphs[sel] .fid 1 =NULL ) { xvt_font_destroy(current->emphs[sel] .fid) , current->emphs[sel] .fid = NULL, xvt_vob3_set_vιsιble(xvt_wιn_get_ctl(w,CStl_DelFont) ,0) ; current->tempmod = 1; curren ->modιfied = 1; CStyleShowFont(w,NULL,current->emphs[sell .style_mask) ,- ) } void XVT_CALLC0NV1 CStyleChangeNesting(WINDOW w) f int sel2; WINDOW bulletnum = xvt_wιn_get_ctl(w,CStl_Num) , if ( xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Style) )==SEL__LIST ) { sel2 = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Nested) ) ; if ( xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Ma3or) )==SEL_ORDERED ) { xvt_lιst_set_sel(bulletnum, -1, false) , xvt_lιst_set_sel(bulletnum,current->lιst_nums[sel2] ,true) , ) else { xvt_lιst_set_sel(bulletnum,-1, false) ; xvt_lιst_set_sel(bulletnum,curren ->lιst_bullets[sel2] .bullet,true) , •if 0 char « pt="", if ( current->lιst_bullets[εel2] .bullet==B_GIF it current->lιst_bullets[sel2] .gιf_name'=NULL ) pt = current->lιst_bullets[sel2] .gιf_na_me; xvt_vob3_set_tιtle(xvt_wιn_get_ctl (w,StlDLG_GIFnaune) ,pt) ) •endif ) ) void XVT_CALLC0NV1 CStyleChangeMa orType(WINDOW w) ( styledlg.c Wad Mar 22 14:42:14 1995 23 int sel, style_type, WINDOW Major, temp; char buf [80], Major - xvt_wιn_get_ctl(w,CStl_Mβ3or) , sel = xvt_lιst_get_sel_ιndex(Major) , style_type = xvt_lιst_get_sel_ιndex(xvt_wιn_get_ctl(w,CStl_Style) ) , if ( style_type == SEL_PARA ) { buff[0]='\0', if { current->paras[sel] colour'=NULL ) strcpy(buff, current->paras[sel] .colour) , xvt_vob 3 _set_tιtle(xvt_wιn_get_ctl(w,CStl_Color) .buff) , sprintf(buff, "%d",current->paras[sel] .indent) , xvt_vob 3 _set_title(xvt_win_get_ctl(w,CStl_First) ,buff) , sprintf(buff, "%d" ,curren ->paras[sel] .sub_ιndent) , xvt_vob3_set_tιtle(xvt_wιn_get_ctl(w,CStl_Subs) ,buff) , sprintf(buff, "%d" ,current->paras(sel] .ιnιt_lead) , xvt_vob3_set_tιtle(xvt_wιn_get_ctl(w,CStl_Lead) ,buff1 , temp = xvt_wm_get_ctl(w,CStl_Alιgn) , xvt_lιst_set_sel(temp, -1, false) , xvt_lιst_set_sel(temp,current->paras[sel] ust, rue) , CStyleShowFont(w,curren ->paras[sel] fid,0L) , } else if ( style_type == SEL_EMPH ) { buff[0)='\0'; if ( current->emphs[sel] colour'=NULL ) strcpylbuff, curren ->emphs[sel] colour), xvt_vob3_set_tιtle(xvt_wιn_get_ctl(w,CStl_Color) ,buff) , if ( current->emphs(sel) .fιd'=NULL it sel'=EM_CachedAnchor ) xvt_vob3_set_vιsιble(xvt_wιn_get_ctl(w,CStl_DelFont) , 1) else -vt_vob3_set_vιsιble(xvt__wιn_get_ctl(w,CStl_DelFont) , 0) , xvt_vob3_set_vιsιble(xvt_wιn_get_ctl (w,CStl_Font) , sel'=EM_CachedAnchor) ,- xvt_lιst_set_sel(xvt_wm_get_ctl(w,CStl_Emph) , TSM_to_Index(current->emphs[sel] style_mask) ,1) , CStyleShowFont(w,current->emphs(sel) .fid,current->emphs[sel] .style_mask) , ) else if ( style_type == SEL_LIST ) { xvt_yob3_set_vιsιble(xvt_wιn_get_ctl(w,CStl_DelFon ) ,0) , sprintf(buff, "%d" ,current->lιst_ιndent) , xvt_vob3_set_tιtle(xvt_wιn_get_ctl(w,CStl_Fιrst) ,buf ) , sprintf (buf f , " %d" , current->lιst_sub ) , xvt_vob 3 _set_tιtle (xvt_wιn_get_ctl (w, CStl_Subs ) . buff ) , sprintf (buff , "%d" , current->lιst_lead) , xvt_vob 3 _set_tιtle (xvt_wιn_get_ctl (w, CStl_Lead) . buff ) , sprintf(buff, "%d",current->ιntralιst_lead) , xvt_vob 3 _set_tltle(xvt_wιn_get_ctl(w,CStl_Wιthιn) .buff) , xvt_vob3_set_vιsιble(xvt_wιn_get_ctl(w,CStl_NumText) ,sel==SEL_ORDERED) , xvt_vob 3 _set_vιsιble(xvt_wιn_get_ctl(w,CStl_BulletText) ,sel'=SEL_ORDERED) temp = xvt_wιn_get_ctl(w,CStl_Num) , xvt_lιst_suspend(temp) ; xvt_lιst_clear(temp) , f ( sel==SEL_ORDERED ) ( xvt_lιst_add(te_np,N_Arab, "Arabic") , xvt_lιst_add(temp,N_SRσman, "Lower case Roman"), xvt_lιst_add(temp,N_CRoman, "Upper case Roman"), xvt__lιst_add(temp,N_SLetter, "Lower case Letters"), xvt_lιst_add(temp,N_CLetter, "Upper case Letters"), } else { xvt_lιst_add(temp,B_FC, "Filled Circle" ) , xvt_lιst_add(temp,B_FS, "Filled Square" ) , xvt_lιεt_add(temp,B_OC, "Open Circle") , xvt_lιst_add(temp,B_OS, "Open Square") , •if 0 xvt_lιst_add(temp,B_GIF, "Picture") •tyladlg.c Wad Mar 22 14 :42 : 14 1995 24 •endif J xvt_lιst_resume(temp) , CStyleChangeNesting(w) , } else { sprintf(buff, "%d",current->prehr_poιnts) , xvt_vob 3 _set_title(xvt_win_get_ctl(w,CStl_Lead) ,buff) , •if 0 buff(0]='\0'; if ( curren ->hr_gιf_name'=NULL ) strcpy(buff, current->hr_gιf_naune) ; xvt_vob 3 _set_title(xvt_win_get_ctl(w,CStl_HRGιf) .buff) , •endif ) ) struct poses { int x,y, ), static struct poses always!] = { { CStl_OK, 410,10 ) , { CStl_Cancel, 410,40 ), •if XVTWS==MTFWS { CStl_StyleText, 19,20 }, { CStl_Ma3orGrp, 10,52 }, •else { CStl_StyleText, 19,12 }, { CStl_Ma3orGrp, 10,46 }, •endif { CStl_Style, 130.10 }, { CStl_Ma 3 or, 130,45 }, -1 ), static struct poses lists!] = ( { CStl_NestedText, 19,101 ), { CStl_NumText, 19,135 ), { CStl_BulletText, 19,135 }, { CStl_FιrstText, 35,191 }, { CStl_FιrstPts, 128,191 }, { CStl_SubsText, 35,221 ), { CStl_SubsPts, 128,221 ), { CStl_LeadText, 222,191 }, ( CStl_LeadPts, 334,191 }, ( CStl_WιthιnText, 222,221 }, { CStl_Wιth nPts, 334,221 }, { CStl_Num, 129,125 ), { CStl_F rst, 90.180 ), { CStl_Subs, 90,213 ), { CStl_Lead, 293,180 }, { CStl_Wιthιn, 293,213 ), •else { CStl_NestedText, 19.93 ), { CStl_NumText, 19.123 ), { CStl_BulletText, 19,123 ), { CStl_FιrstText, 35.183 ), { CStl_FιrstPts, 128,183 ), { CStl_SubsText, 35,213 }, { CStl_SubsPts, 128,213 }, { CStl_LeadText, 222,183 ), Wad Mar 22 14:42:14 1995 25 .LeadPts, 354,183 }, .WithinText, 222,213 ), .WithinPts, 354,213 ), .Nu , 129,120 ) , .First, 80,180 ), .Subs, 80,213 ), .Lead, 303,180 ), .Within, 303,213 ), .Nested, 129,91 }, .IndText, 19,160 }, .LeadingText, 204,160 ), static struct poses emphε[] = I { CStl_Help, 410 150 ), •if XVTWS==MTFWS { CStl_EmphText, 19,101 }, { CStl_ColorText 19,135 }, { CStl_FontDesc, 10,258 }, { CStl_DescText, 16.278 ), { CStl_Color. 130,125 }, •else { CStl_E_τ_phText, 19,93 ), { CStl_ColorText , 19,123 }. { CStl_FontDesc, 19,248 ), { CStl_DescText. 25,268 }, { CStl_Color, 13 0,121 ). •endif { CStl_Eπτph. 129 ,91 ), { CStl_Font , 410,80 ) , { CStl_DelFont , 410,110 ), -1 ); static struct poses hrs [ ] = { { CStl_Help, 410,80 }, •if XVTWS==MTFWS { CStl_LeadingText, 19,101 { CStl_IniTex , 35,126 ), { CStl_LeadPts, 128,126 ), •else { CStl_LeadingText, 19,93 { CStl_IniText, 35,118 ), { CStl_LeadPts, 128,118 }, •endif ( CStl_Lead, 80.115 ), -1 ); static struct poses paras [ ] = { { CStl_Help, 410,122 ), •if XVTWS==MTFWS ( CStl_AlignText, 19,101 }, { CStl_ColorText, 19,131 { CStl_FirstText, 35,191 { CStl_FirstPts, 128.191 { CStl_SubsText, 35,221 { CStl_SubsPts, 128,221 { CStl_IniText, 222,191 { CStl_LeadPts, 334,191 CStl_FontDesc, 10,258 ) 26 ); static struct dones { int cid, done; } dones[] = { {CStl_NestedText} , (CStl_Nested) , (CStl_NumText) , {CStl_BulletText} , (CStl_Num) , (CStl_IndText) , (CStl_FirstText} , (CStl_First) , {CStl_FirstPts} , (CStl_SubsText) , {CStl_Subs), {CStl_SubsPts} , {CStl_LeadingText}, {CStl_LeadText} , {CStl_Lead), {CStl_LeadPts), {CStl_WithinText} , (CStl_Within), {CStl_WithinPts}, {CStl_EmphText} , (CStl_E_nph) , {CStl_ColorText} , (CStl_Color) , (CStl_Font) , (CStl_DelFont) , (CStl_FontDesc), (CStl_DescText) , (CStl_AlignText), (CStl_Align) , (CStl_IniText) , -1 ); static void cleardone(void) { int i; ■tyladlg.c Wad Mar 22 14 :42 : 14 1995 27 for ( ι=0 , dones [ I ] . cid ' = - 1 , ++ι ) dones [ l ] . done = false, } static void markdone{int cid) { int l, for ( ι=0; dones[i] .cιd'= -1 ; ++ι ) if ( dones(I) .cιd==cιd ) { doneε[i] .done = true; return,- ) ) static void invisibleundone(WINDβW w) { int i; for ( ι=0; don*-' _.].cιd'= -1 , ++ι ) xvt_vob3__et_vιs■ le(xvt_wιn_get_ctl(w,dones[i] .cid) ,dones[I] .done) , ) static void moveto(..'I.JDOW w, struct poses "pos, int mark) { RCT ret; WINDOW tnir = xvt_wιn__get_ctl(w,pos->cιd) , xvt_vob3_get_outer__rect(thing,tret) , if ( pos->x'=rct.le | | pos->y'=rct.top ) { ret.bottom += pos->y-rct.top; ret.right += pos->x-rct.left, ret.top = pos->y; ret.left = pos->x, •if XVTWS==MTFWS if ( pos->cιd==CStl_OK I I pos->cιd==CStl_Cancel ) { /" These two are magic, th e reported size is not the real size */ ret.bottom ♦= 12, if ( pos->cιd==CStl_OK ) { ret.left -= 6, ret.right += 6; } else ret.right += 12; } else if ( pos->cιd==CStl_Fιrst | | pos->cιd==CStl_Subs | | pos->cιd == CStl_Lead | | pos->cιd == CStl_Wιthιn ) ( ret.right = rct.left+34, ) else if ( pos->cιd==CStl_WιthιnText ) { ret.right = ret.left+70; } else if ( pos->cιd==CStl_SubsText ) { ret.right = rct.left+50; } •elif XVTWS«WINWS { WIN_TYPE wt = xvt_vobj_get_type(thing) ; lf(wt == WC_LISTBUTTON || wt == WC_LISTEDIT) ret.bottom += 0x80; } •endif xvt_vob3_move(thing,tret) ; ) if ( mark ) markdone(pos->cιd) , ) static void moveall (WINDOW w, struct poses *pos, int mark) ( cleardone() ; while ( pos->cιd'=-l ) { moveto(w,pos,mark) ; ++pos; atyladlg.c Wad Mar 22 14 :42 : 14 1995 28 ) ιnvιsιbleundone (w) ; ) static void ImtList (WINDOW w, int cid, char "pnaunes ) { WINDOW Major ; xvt_lιst_cl ear (Major = xvt_wιn_get_ctl (w, cid) ) , for ( ι=0 ; pnaunes [ l ] ' =NUL ; + + ι ) xvt_list_ad (Major , ι , pnames [ ι ] 1 ; xvt_lιst_set_sel (Major , 0 , 1 ) ; ) static void InitStyleList (WINDOW w, mt cid) { WINDOW Styles ; STYLE *stl , *cs ; int cur=0 , I ; View 'view = (View * ) xvt_vobj_get_data (w) ; cs = current; if ( vιew'=NULL it vιew->tag==TAG_VIEW ) cs = vιew->sheet; xvt_lιst_clear(Styles = xvt_wιn_get_ctl(w,cid) ) , for ( stl= inormalspam, ι=0; stl!=NULL, stl=stl->nex , ++ι ) ( xvt_lιst__add(Styles,l,stl->name) ; if I stl==cs ) cur = i, ) xvt_lιst_set_sel (Styles,cur,1) , ) void XVT_CALLCONVl CStyleChangeStyle(WINDOW w) { int style_type = xvt_lιst_get_sel_ιndex(xvt_w n_get_ctl(w,CStl_Style) ) , static char "Inames[] = { "OrderedList", "UnorderedList" , NULL } ,- char ord[60], unord[60] ; if ( style_type==SEL_PARA ) { ImtList(w,CStl_Major,pnames) ; moveall(w,paras,true) ; } else if ( style_type==SEL_EMPH ) { ImtList(w,CStl_Major,enames) ; moveal1( ,emphs,true1 ; } else if ( style_type==SEL_LIST ) { Inames[0]=xvt_res_get_str(Style_Ordered,ord,sizeof(ord) ) ,- Inames[l]=xvt_res_get_str(Style_Unordered,unord,εizeof (unord) ) ; ImtList(w,CStl_Major,lnaunes) ; moveall (w,lists,true) .- Rule", Inames[1]=NULL; ImtList(w,CStl_Ma or,Inames) ; moveall(w,hrs,true) , ) CStyleChangeMajorType(w) ; ) void XVT_CALLCONVl CStyleFiHup(WINDOW w) { WINDOW list; moveall (w,always,false) ; list = xvt_wιn_get_ctl(w,CStl_Style) ; xvt_lιst_suspend(lιst) ; xvt_lιst_clear(list) ; xvt_lιst_add(lιst,SEL_PARA, "Paragraphs" ) , xvt_lιεt_add(lιst,SEL_EMPH, "Emphaseε") , styledlg.c Wad Mar 22 14:42:14 1995 29 xvt_list_add(list,SEL_LIST, "Lists") ,- xvt_list_add(list,SEL_HR, "Horizontal Rule") ; xvt_list_resume(list) ; list = xvt_win_get_ctl (w,CStl_Nested) ; xvt_list_suspend(list) ,- xvt_list_clear (list) ; xvt_list_add(list, 0, "1"] xvt_list_add(list,l, "2") , xvt_list_add(list,2, "3") , xvt_list_add(list,3, *4") , xvt_list_resume(list) ; list = xvt_win_get_ctl (w,CStl_Align) ; xvt_list_suspend(list) ; xvt_list_clear (list) ,- xvt_list_add(list, J_Lef t, "Left" ) ; xvt_list_add(list, J_Center, "Center" ) ; xvt_list_add(list, J_Right, "Right") ,- xvt_list_add(list, _Filled, "Filled") ; xvt_list_resume(list) ,- InitList (w,CStl_Emph, snaunes) ; SetColourList (xvt_win_get_ctl (w,CStl_Color) , true) CStyleChangeStyle(w) ; ) praaa Sat Mar 25 10:29:33 1995 Main body of code for the client User interface routines start with NP. -rw-r—r-- 2213 Mar 22 16 -rw-r—r-- 3724 Mar 22 16 -rw-r—r-- 3100 Mar 22 16 -rw-r—r-- 3501 Mar 22 16 -rw-r--r-- 3211 Mar 22 16 -rw-r--r-- 2677 Mar 22 16 -rw-r—r— 4232 Mar 22 16 -rw-r—r— 6127 Mar 22 16 -rw-r--r-- 2313 Mar 22 16 -rw-r--r-- 4081 Mar 22 16 -rw-r--r-- 3307 Mar 22 16 -rw-r—r-- 2723 Mar 22 16 -rw-r—r-- 4720 Mar 22 16 -rw-r--r-- 4183 Mar 22 16 -rw-r—r— 3744 Mar 22 16 -rw-r--r-- 2602 Mar 23 15 -rw-r--r— 3512 Mar 22 16 -rw-r--r— 7195 Mar 22 16 -rw-r--r-- 4376 Mar 22 16 -rw-r--r— 2697 Mar 22 16 -rw-r--r-- 2930 Mar 22 16 -rw-r--r-- 2561 Mar 22 16 -rw-r--r-- 7237 Mar 22 16 -rw-r--r-- 12323 Mar 23 14 -rw-r—r— 7958 Mar 22 16 -rw-r--r-- 5619 Mar 22 16 -rw-r--r-- 4030 Mar 22 16 -rw-r—r-- 4232 Mar 22 16 -rw-r--r-- 4115 Mar 22 16 -rw-r—r-- 3351 Mar 22 16 -rw-r—r— 4812 Mar 22 16 -rw-r--r-- 3282 Mar 22 16 -rw-r--r-- 1095 Mar 22 16 -rw-r~r— 4892 Mar 22 16 -rw-r~r— 3229 Mar 22 16 -rw-r—r-- 2844 Mar 22 16 -rw-r—r-- 4624 Mar 22 16 -rw-r—r— 5576 Mar 22 16 -rw-r—r-- 4628 Mar 22 16 -rw-r—r— 10186 Mar 22 16 -rw-r—r— 48790 Mar 22 16 lrwxrwxrwx 14 Mar 22 18 -> raw/authentc.c lrwxrwxrwx 11 Mar 22 18 raw/bkgnd.c lrwxrwxrwx 14 Mar 22 18 -> raw/callback.c lrwxrwxrwx 14 Mar 22 18 callback.h -> raw/callback lrwxrwxrwx 13 Mar 22 18 chooser.c -> raw/chooser.c lrwxrwxrwx 13 Mar 22 18 chooser.h -> raw/chooser.h lrwxrwxrwx 13 Mar 22 18 cursors.h -> raw/cursors.h lrwxrwxrwx 13 Mar 22 18 destdlg.c -> raw/destdlg.c lrwxrwxrwx 9 Mar 22 18 48 doc.h -> raw/doc.h lrwxrwxrwx 14 Mar 22 IB 48 doccache.c -> raw/doccache. lrwxrwxrwx 13 Mar 22 18 48 docedit.c -> raw/docedit.c lrwxrwxrwx 14 Mar 22 18 48 docgraph.c -> raw/docgraph. lrwxrwxrwx 14 Mar 22 18 48 docrefer.c -> raw/docrefer. lrwxrwxrwx 13 Mar 22 18 48 docview.c -> raw/docview.c lrwxrwxrwx 12 Mar 22 18 48 fields.c -> raw/fields.c lrwxrwxrwx 10 Mar 22 18 48 find.c -> raw/find.c lrwxrwxrwx 13 Mar 22 18 48 fldedit.c -> raw/fldedi .c lrwxrwxrwx 10 Mar 22 18 48 func.h -> raw/ unc.h praaa βat Mar 25 10:29:33 1995 lrwxrwxrwx root 18:48 help.c -> raw/help.c lrwxrwxrwx root 18:48 historyd.c -> raw/historyd.c lrwxrwxrwx root 18:48 hooksmac.c -> raw/hooksmac.c lrwxrwxrwx root 18:48 hooksmsw.c -> raw/hooksmsw.c lrwxrwxrwx root 18:48 hooksx.c -> raw/hooksx.c lrwxrwxrwx root 18:48 hotlist.c -> raw/hotlist.c lrwxrwxrwx root 18:48 html.c -> raw/html.c lrwxrwxrwx root 18:48 html.h -> raw/html.h lrwxrwxrwx root 18:48 htmlerrs.c -> raw/htmlerrs.c lrwxrwxrwx root 18:48 imgcache.c -> raw/imgcache.c lrwxrwxrwx root 18:48 mits.c -> raw/inits.c lrwxrwxrwx root 18:48 keymore.h -> raw/keymore.h lrwxrwxrwx root 18:48 linkchck.c -> raw/linkchck.c lrwxrwxrwx root 18:48 makemap.c -> raw/makemap.c lrwxrwxrwx root 18:48 navilink.c -> raw/navilink.c lrwxrwxrwx root 18:48 pagcache.c -> raw/pagcache.c lrwxrwxrwx root 18:48 prefs.c -> raw/prefs.c lrwxrwxrwx root 18:48 source.c -> raw/source.c -rw-rw-rw- dave 16:17 stamp.c lrwxrwxrwx root 18:48 stamper.c -> raw/stamper.c lrwxrwxrwx root 18:48 style.h -> raw/style.h lrwxrwxrwx root 18:48 styledlg c -> raw/styledlg c lrwxrwxrwx root 18:48 undo.c -> raw/undo.c lrwxrwxrwx root 18:48 undo.h -> raw/undo.h lrwxrwxrwx root 18:48 url.c -> raw/url.c lrwxrwxrwx root 18:48 util.c -> raw/util.c lrwxrwxrwx root 18:48 view.c -> raw/view.c lrwxrwxrwx root 18:48 view.h -> raw/view.h lrwxrwxrwx root 18:48 viewcmd.c -> raw/viewcmd.c lrwxrwxrwx root 18:48 viewcol.c -> raw/viewcol.c lrwxrwxrwx root 18:48 viewdraw.c -> raw/viewdraw.c lrwxrwxrwx root 18:48 viewedit.c -> raw/viewedit.c lrwxrwxrwx root 18:48 viewfrmt.c -> raw/viewfrm .c lrwxrwxrwx root 18:48 viewins.c -> raw/viewms.c lrwxrwxrwx root 18:48 viewsave.c -> raw/viewsave.c lrwxrwxrwx root 18:48 viewsel.c -> raw/viewsel.c lrwxrwxrwx root 18:48 viewutil.c -> raw/viewutil.c lrwxrwxrwx root 18:48 winmenu.c -> raw/winmenu.c lrwxrwxrwx root 18:48 xvtjpeg.c -> raw/xvtjpeg.c lrwxrwxrwx root 18:48 xvtxbm.c -> raw/xvtxbm.c lrwxrwxrwx root 18:48 xxinit.c -> raw/xxinit.c Files included for reference: NPChoose.c: interface for local and remote file chooser NPDoc.c: interface for collections NPDocMn.c: interface for collections menu NPNewStl.c: interface for styles NPNvLink.c: interface for autogeneration of links NPPage.c: interface for page window NPPageMn.c ■ interface for page menu NPStyle.c: interface for styles chooser.c • local remote file system selection callback.c: client-server communications 25 10:29:33 1995 3 to implement collections to implement edit functions collections to implement graphing of collections to implement collections to implement collections to implement autogeneration of links to implement styles to implement copy and paste address functions ans writes pages page editing functions praaa βat Mar 25 10:29:33 1995 Main body of code for the client User interface routines start with NP. 11 NPAbout.c 11 NPAboutW.c 11 NPAu hen.c 11 NPChkLnk.c 11 NPChoose.c 11 NPDest.c 30 NPDoc.c 11 NPDocMn.c 11 NPError.c 11 NPFindRp.c 41 NPForm.c 11 NPHistor.c 11 NPHotLst.c 11 NPImgFld.c 11 NPInsImg.c 13 NPLatin.c 11 NPLink.c 11 NPMap.c 11 NPMime.c 11 NPNewStl.c 11 NPNvLink.c 11 NPOpnOpt.c 30 NPPage.c 55 NPPageMn.c 11 NPPalet.c 11 NPPrfGen.c 11 NPRadio.c 11 NPRefBy.c 11 NPRefTo.c 11 NPSavOpt.c 11 NPSelLst.c 11 NPSrc.c 11 NPSrcMn.c 11 NPStlCha.c 11 NPStyle.c 11 NPSubmit.c 11 NPTaskMn.c 43 NPTextAr.c 11 NPTxtFld.c 11 NaviPres.c 11 NaviPres.h 48 authentc.c -> raw/authentc.c 48 bkgnd.c -> raw/bkgnd.c 48 callback.c -> raw/callback.c 48 callback.h -> raw/callback.h 48 chooser.c -> raw/chooser.c 48 chooser.h -> raw/chooser.h 48 cursors.h raw/cursors,h 48 destdlg.c -> raw/destdlg.c 48 doc.h -> raw/doc.h 48 doccache.c -> raw/doccache.c 48 docedit.c -> raw/docedi .c 48 docgraph.c -> raw/docgraph.c 48 docrefer.c -> raw/docrefer.c 48 docview.c -> raw/ ocview.c 48 fields.c -> raw/fields.c 48 find.c -> raw/find.c 48 fldedit.c -> raw/fldedit.c 48 func.h - > raw/func.h praaa βat Mar 25 10:29:33 1995 lrwxrwxrwx root 10 Mar 22 18:48 help.c -> raw/help.c lrwxrwxrwx root 14 Mar 22 18:48 historyd.c -> raw/historyd.c lrwxrwxrwx root 14 Mar 22 18-48 hooksmac.c -> raw/hooksmac.c lrwxrwxrwx root 14 Mar 22 18:48 hooksms .c -> ra /hooksmsw.e lrwxrwxrwx root 12 Mar 22 18:48 hooksx.c -> raw/hooksx.c lrwxrwxrwx root 13 Mar 22 18:48 hotlist.c -> raw/hotlist.c lrwxrwxrwx root 10 Mar 22 18:48 html.c -> raw/html.c lrwxrwxrwx root 10 Mar 22 18:48 html.h -> raw/html.h lrwxrwxrwx root 14 Mar 22 18:48 htmlerrs.c -> raw/htmlerrs.c lrwxrwxrwx root 14 Mar 22 18:48 imgcache.c -> raw/imgcache.c lrwxrwxrwx root 11 Mar 22 18:48 mits.c -> raw/mits.c lrwxrwxrwx root 13 Mar 22 18:48 keymore.h -> raw/keymore.h lrwxrwxrwx root 14 Mar 22 18.48 linkchck.c -> raw/linkchck.c lrwxrwxrwx root 13 Mar 22 18:48 makemap.c -> raw/makemap.c lrwxrwxrwx root 14 Mar 22 18:48 navilink.c -> raw/navilink.c lrwxrwxrwx root 14 Mj»r 22 18:48 pagcache.c -> raw/pagcache.c lrwxrwxrwx root 11 Mar 22 18:48 prefs.c -> raw/prefε.c lrwxrwxrwx root 12 Mar 22 18:48 source.c -> raw/source.c -rw-rw-rw- dave 46 Mar 24 16:17 stamp.c lrwxrwxrwx root 13 Mar 22 18:48 stamper.c -> raw/stamper.c lrwxrwxrwx root 11 Mar 22 18:48 style.h -> raw/εtyle.h lrwxrwxrwx root 14 Mar 22 18:48 styledlg.c -> raw/εtyledlg.c lrwxrwxrwx root 10 Mar 22 18:48 undo.c -> raw/undo.c lrwxrwxrwx root 10 Mar 22 18:48 undo.h -> raw/undo.h lrwxrwxrwx root 9 Mar 22 18:48 url.c -> raw/url c lrwxrwxrwx root 10 Mar 22 18:48 util.c -> raw/util.c lrwxrwxrwx root 10 Mar 22 18:48 view.c -> raw/view.c lrwxrwxrwx root 10 Mar 22 18:48 view.h -> raw/view.h lrwxrwxrwx root 13 Mar 22 18:48 viewcmd.c -> raw/viewcmd.c lrwxrwxrwx root 13 Mar 22 18:48 viewcol.c -> raw/viewcol.c lrwxrwxrwx root 14 Mar 22 18:48 viewdraw.c -> raw/v ewdraw.c lrwxrwxrwx root 14 Mar 22 18:48 viewedit.c -> raw/viewedit.c lrwxrwxrwx root 14 Mar 22 18:48 viewfrmt.c -> raw/viewfrmt.c lrwxrwxrwx root 13 Mar 22 18:48 viewinε.c -> raw/viewinε.c lrwxrwxrwx root 14 Mar 22 18:48 viewsave.c -> raw/viewsave.c lrwxrwxrwx root 13 Mar 22 18:48 viewsel.c -> raw/viewsel.c lrwxrwxrwx root 14 Mar 22 18:48 viewutil.c -> raw/viewutil.c lrwxrwxrwx root 13 Mar 22 18:48 winmenu.c -> raw/winmenu.c lrwxrwxrwx root 13 Mar 22 18:48 xvtjpeg.c -> raw/xvtjpeg.c lrwxrwxrwx root 12 Mar 22 18:48 xvtxbm.c -> raw/xvtxbm c lrwxrwxrwx root 12 Mar 22 18:48 xximt.c -> raw/xximt.c Files included for reference: NPChoose.c. interface for local and remote file chooser NPDoc.c: interface for collections NPDocMn.c: interface for collections menu NPNewStl.c: interface for styles NPNvLink.c: interface for autogeneration of links NPPage.c: interface for page window NPPageMn.c- interface for page menu NPStyle.c: interface for styles chooser.c: local remote f le system selection callback.c: client-server communications 25 10:29:33 1995 3 to implement collections to implement edit functions collections to implement graphing of collections to implement collections to implement collections to implement autogeneration of links to implement styles to implement copy and paste address functions ans writes pages page editing functions ▼iβwβava.c Tua Mar 21 10:24:14 1995 1 /* Copyright 1994-1995 NaviSoft, Inc All rights reserved */ •include <xvt.h> •include <stdιo.h> •include "func.h" •include "htrol.h" •include "view.h" •include "doc.h" •include "NaviPres.h" •include "xlocal.h" •include "guess.h" •include "chooser.h" /"""""""/ •if XVT_OS_ISUNIX static void XVT_CALLC0NV1 ViewSaveAsPostscrip (View 'view, char 'name) { xvt_vob3_set_attr(NULL_WIN, ATTR_PS_PRINT_FILE_NAME, (long) name ), ViewPrint(vιew->w) , xvt_vob3_set_attr(NULL_WIN, ATTR_PS_PRINT_FILE_NAME, (long) 0 ), ) •endif /* Figure out what the legal file types are on the machine on which the file */ /* lives. Remote machines are all assumed to be unix */ static enum fιleneune_type NameTypeOfFilelchar "urll ( if ( XVT_OS_ISUNIX || fsys_ιε_url(url) ) return! fn_posιx 1 ; else if ( XVT_OS_IS_WINOS ) return( fn_dos ) ; else return( fn_mac ) , ) static char "AskForNa e(char 'name. Document *doc) { char 'buffer, 'ret, fname[100], DocPart 'dp; int sizebuf,- strncpy(fname, fsys_nametaιl(name) ,εizeof(fname) -1) , fname[sizeof(fname)-1]= '\0', buffer = myalloc(sizebuf=strlen(name)+30) , while (1) ( if (xvt_dm_post_strιng_prompt("Rename to ", fnaune,sizeof(fname) )==NULL | | fname[0]=='\0' ) { myfree(buffer) ; return( NULL ) ; ) fsyε_replace_name(name, fname,buffer,sizebuf) ; if ( fsys_badname(buffer,doc'doc->nametype-fn_local) ) ( navι_dm_post_error(Attrdlg_BadName) , continue; } else if ( doc'=NULL it <dp=LookupDocPar (doc, fname) )'=NULL it dp->exιstε ) continue; else if I doc==NULL tt url_exιstε(buffer) ) continue, ret = copy(buffer) ; myfree(bu fer) ,- return( ret 1 ; ) ) /* Save an image locally Figure out if the image lε in the same "directory" */ /* as the page we got it from, if so tnen always save it, otherwise only save*/ viβwβa-e.c Tua Mar 21 10:24 :14 1995 2 / * if saveιmages==2 (save all images ) * / int XVT_CALLCONVl GenerateSaveNaune (char "oldurl , char "mainurl , char "toname, int saveimages , char "buffer , int size . Document "doc l { char "pt ; int ret; if ( saveimages < =2 it fsyε_ιε_url (oldurl ) ) return ( 0 ) ; pt = fsys_n__metail (oldurl) ; if ( saveιmages==3 tt pmatch! ■ */* • ,guess_suffix(pt) ) ii pmatch ( "text/html ", fsys_lookupsuffix(oldurl) ) ) { /* We don't know what t is. If it is to be local we should give it */ /* a name that we can recognize (if it is something we- need to */ /* recognize) */ char *pt, *nt, ntbuf [100); nt = fsys_makerealname(oldurl,ntbuf, sizeof (ntbuf) ,doc->nametype) ,- fsys_buιld_naune(doc->name,nt,buffer,size) ; pt = strchr(fsys_name aιl (buffer), ' .') , if ( pt==NULL ) pt = buffer+strlen(buffer) ; if ( doc->naunetype==fn_dos ) strcpy(pt, " .htm* ) ,- else strcpy(pt, " .html" ) ,- ) /* pt now points to the filename portion of the image' s url * / f sys_replace_n_une ( toname , pt , buffer , size ) ; if I fsys_ba dnaune (buf fer, doc?doc->naunetype : fn_local ) ) f syε_makegoodname (buf f er, doc?doc->neunetype : f n_local ) , if ( fsys_exιsts (buf er) ) { ret = navι_dm_post_ask ( Genera l_Save/ * "Save " * / , General_Rename , Geneιal_DontSave/ * "Do n' t Save* * / , Vιewsave_Exιsts/* "Fιle % .100s already exists , save anyway'" * / , buffer ) if ( ret==RESP_3 ) return(O) ; if ( ret==RESP_2 ) { pt = AskForName(buffer,doc) , strncpy(buffer.p ,size) ,- buffer [sιze-l]=' .0' ; myfreel t) ; ) ) return( 1 ) ,- ) /* Save an image locally. Figure out if the image is in the same "directory" */ /* as the page we got it from, if so then always save it (if saveimages) , */ /* otherwise only save if saveιmages==2 (save all images) . Also deal w th */ /* having to change filenames (because the OS only supports 8.3 names), some-*/ /* times we must perform a name fixup even if we don't save the file */ static int XVT_CALLC0NV1 Savelmage(char 'imageurl, char "mainurl, char 'tonaune, int saveimages, t rpl. Document "doc. Page "page, char 'buffer, mt sizebuf, Form "already, mt checkname) { char *buf2, anchor(40] ; int sizebuf2, mt ret; char *pt; buf2 = myalloc (sιzebuf2 = εtrlen(imageurl) +strlen(mainurl) +30) ; URLTrans(imageurl,mainurl,NULL,buf2,anchor,sizebuf2 , sizeof (anchor) ) , if ( saveimages"0 tt rpl ) { ▼iawaa-a.c Tua Mar 21 10:24:14 1995 3 /* Don't same the image, but do make the name absolute */ strncpy(buffer,buf2,sizebuf) ; buffer[sizebuf-1]=' \0' , if { anchor[0] '='\0' tt strlentbuffer)+2>sιzebuf ) ( strcat(buffer, "#") ; strncpylbuffer+strlen(buffer) ,anchor,sizebuf-strlen(buffer) ) ,- buffer[sιzebuf-l]='\0' , } myfree(buf2) ; return 1; } lflpt = GetFormValue(already, buf2)) { strcpy(buffer.pt) ; /* We may need to rename it */ return 1; /' So pretend we did something */ ) if ( !saveimages tt ( 'checkname | | ' fsys__badname(buf2,doc?doc->nametype:fn_local) ) 1 { myfree(buf2) ; return 0; /' No fixup needed */ ) if ( !fεys_ιs_url (imageurl) ) /* naune tail may not work on imageurl */ pt = fsys_nametaιl(buf2) , /* if it lε a relative umx name on a */ else '* doε system, but we need to know that*/ pt = buf2; /* it was rel. so can't use buf2 either*/ ret = GenerateSaveName(pt,mainurl,tonaune,εaveimages,buffer,sizebuf,doc) , AppendFormField(already, buf2, buffer, 0, 0) ; if ( !saveimages | | ret<=0 ) { if ( ret==0 ) ret=l; /* Don't copy, still may need name fixup */ return( ret ) ; } if ( page->vιews'=NULL ) ViewsImageChange(page, ImageCopy(buffer,imageurl,mainurl) ,buf2) ; ret = CopyURLToFile(buf2,buffer,doc) ; myfree(buf2) ; return( ret ) ; ) /* Save a style sheet locally. Figure out if the image is in the same "directory" */ /* as the page we got t from, if so then always save it, otherwise only save*/ /* if saveιmages==2 (save everything) */ static mt XVT_CALLC0NV1 SaveStl (STYLE *stl, char 'mainurl, char 'toname, int saveimages, Document *doc. Page "page) { char 'buffer; mt ret, sizebuf; if ( stl==normalstyle ) /* Don't save the default style */ returnI 1 ) ,- buffer = myalloc(sizebuf = strlen(stl->name)+strlen(mainurl)+30) ; if (( ret = GenerateSaveNameIstl->name, ainurl, oname,saveimages,buffer, sizebuf,doc) )<=0 ) { myfree(buffer) ; return( ret ) ; ) myfree(page->style) ; page->style = copy(fsys_nametaιl(buffer) ) ; ret = SaveStyle(stl,buffer,saveimages,doc,page) ; myfreeIbu fer) ; returnI ret ) ; ) /* Save an image map file: Load t in, process it to tweak links, then save */ /* to new place */ static int XVT_CALLCONVl SaveMaplchar "mapurl, char "mainurl, char 'tonaune, int replacelinks, Document *doc. ▼iawaava.c Tua Mar 21 10:24:14 1995 char 'buffer, t sizebuf, Form 'already) { char *buf2; int sizebuf2; char *p ; buf2 = myalloc(sizebuf2 = strlen(mapurl)+strlen(mainurl)+30) URLTrans(mapurl.mainurl, ULL,buf2,buffer,sizebuf2,sizebuf) ; ιf(pt = GetFormValue(already, buf2)) { strcpy(buffer.pt) , We may need to rename it */ return 1; So pretend we did something '/ ) if !fsys_ιs_url(mapurl) ) /' name tail may not work on mapurl */ pt = fsys_naunetaιl(buf2) ,- ι * if it is a relative u x name on a */ else /' dos system, but we need to know that*/ pt = bu 2; /' it was rel, so can't use buf2 either*/ ret = GenerateSaveName(pt,mainurl,toname,1,buffer,sizebuf,doc) , AppendFormField(already, buf2, buffer, 0, 0), if ( ret>=0 ) ret = CopyMapToMap(bu 2,buf er,replacelιnkε,doc) ; myfree(buf2) ; return( ret ) ; ) struct saveasctx { unsigned int saveimages: 2; unsigned int replacelinks: 1 enum ιlename_type from, to; char Oldurl; char 'newname Document *doc Form 'already don't include images more than once.. ); static char 'InsAttr(char 'next, char 'tagtext, int taglen, mt tag, char 'name) ( char buffer[100] ; if ( _HTML_HasAttr(tagtext,taglen,tag,buffer,sizeof(buffer) .naune) ) ( if ( buffer[0]=='\0' tt HTML_AttrValue( ag,naune) ) { sprintf(next, " %s=\"\"", naune), 'next = ' ' ; strcp (next+1,name) ; ) else sprintf(next, " %s=\"%s\"" , naune, buffer); next += strlen(nex ) ; ) return(next) ; ) static t XVT_CALLC0NV1 ReplacelmagelPage 'page, Para 'para, char 'tagtext, mt oldlen, char *buf, nt len, int ιs_undo) { int diff, off; if ( tagtext==para->tagtext ) { buf += HTML_HEAD_LEN; len -= HTML_HEAD_LEN; if ( !ιs_undo ) UndoAddTagText(page,falεe,para->pnum,copyn(tagtext,oldlen) ) , αf ( oldlen>=len ) ( memcpy(tagtex ,buf,len) ; ) else { para->tagtext = copynlbuf,len) ; myfree(tagtext) , viβw_.a-».c Tua Mar 21 10:24:14 1995 5 } ) else { tagtext -= HTML_HEAD_LEN; oldlen += HTML_HEAD_LE ; if ( 'ιs_undo ) UndoAddLitteral(page,false,para->pnum,tagtext-para->tex , para->pnum, tagtext-para->text+len, copyn(tagtext,oldlen) ) ,- if ( oldlen<len ) ( off = tagtext-para->text; d ff = len-oldlen; if ( para->tlen+dιff+l>-para->tmax ) para->text = myrealloc(para->tex ,para->tmax += dιff+10); for ( ι=para->tlen; >=off+oldlen; --ι ) para->text[ι+dιff] = para->tex [i] , memcpy(para->text+off,buf,len) ; para->tlen += diff, } else ( memcpy(tagtext,buf,len) ,- if ( len'=oldlen ) memcpy(tagtext*len,tagtext+oldlen,para->tlen- (tagtext+oldlen-para->text)+1 ), para->tlen -= oldlen-len, ) ) page->saveasaltered = true; return 1, ) static void _UndoSaveAs(Page 'page. Undo 'actor) { Para "para; para = PageGetPara(page,actor->pnums) ; if ( actor->type"u_lιtteral ) { Replacel age(page, para, para->text+actor->offsets+HTML_HEAD_LEN, actor->offsete-actor->offsets-HTML_HEAD_LEN, actor->str, HTML_len(actor->str) .true) ; ) else if ( actor->type == u_tagtext ) { char 'temp = para->tagtext; para->tagtext = actor->str; actor->str = NULL; myfree(temp) ; ) else if ( actor->type == u_multιple ) { Undo 'subs, 'psub; for ( εubs=actor->sub; subs'=NULL; subs=psub ) { psub = subs->prev; _UndoSaveAs(page,subs) ; ) actor->sub = NULL; '/' We already freed them */ ) else IError("UndoSaveAs: Can't get here") ; actor->prev = NULL; UndoFree!actor) ; ) void UndoSaveAsIPage 'page) { Undo 'actor = page->undoes; if ( actor«NULL ) return; page->undoeε = actor->prev; _UndoSaveAs(page, ctor) ; ) static int XVT_CALLC0NV1 pupdateimages(Page 'page, Para 'para, int tag, int taglen, char * ▼iβwaa-a .c Tua Mar 21 10 : 24 : 14 1995 6 tagtext, void *vctx) { struct saveasctx "ctx = (struct saveasctx * ) vctx; char 'oldname = ctx->oldurl ; char 'newname = ctx->newnaune,- mt saveimages = ctx->saveιmages ; char *pt , 'next ; char 'buffer, *buf, anchor[100); t sizebu f, sizebuf; int ret, samedir; if ( ( tag=-IMG_TAG || tag==INPUT_TAG) ti (ctx->replacelmkε j| saveimages | | ctx->from >ctx->to)) { buffer = myalloc ; if ( _HTML_HasAttr(tagtext,taglen,tag,buffer,sizebuff, "SRC") ) { buf = myalloc(sιzebuf=strlen(buffer)+strlen(newname)+300+30) , if ((ret = SaveImage(buffer,oldname,newname,saveimages, ctx->replacelmks,ctx->doc, page,buf.sizebuf,ctx->already,ctx->from>ctx->to) )==-l ) ( myfreetbuffer) ; myfree(buf) ; return(0). /* Cancelled */ ) if ( ret ) strcpy(anchor, fsys_nametaιl(buf) ) ; if ( ret tt ( (pt = fsys_nametaιl(buffer) ) '=buffer | | strcmp(pt,anchor) !=0 || (saveιmages==0 it ctx->replacelιnks ti strcmplbuf.buffer) '=0) ) ti (saveιmages-=2 || !fsys_ιs_url(buffer)) ) { if I saveιmages==0 tt ctx->replacelιnks ) strcpylbuffer.buf) ; HTML_FιllTag(buf.tag) ; next = buf+HTML_HEAD_LEN; strcpy(next,tag==IMG_TAG ? " SRC=":" TYPE=IMAGE SRC="1; strcpy(next+strlen(next) , (saveimages==0 tt ctx->replacelιnks)?buffer:anchor) , next += strlen(next) ; next = InsAttr(next,tagtext,taglen,tag, "ALIGN" 1 , if ( tag==IMG_TAG ) { next = InsAttr(next,tagtext,taglen, tag, "ALT"1 ; next = InsAttr(next,tagtext,taglen,tag, "ISMAP") ,- } else { next = InsAttr(next,tagtext,taglen, tag, "NAME") , } buf[HTML_LEN_LOW] = strlen(buf+HTML_HEAD_LEN)%256; buf[HTML_LEN_HIGH] = strlen(buf+HTML_HEAD_LEN)/256, Replacelmage(page,para,tagtext,taglen,buf,HTML_HEAD_LEN+strlen(buf+HTML_HE AD_LEN) , false) ; ) { ctx->replacelιnks = true; if ( _HTML_HasAttr(tagtext, taglen,tag,buffer,sizebuff,tag==A_TAC"HREF" . "ACTION" 1 ) { /* Links to the current file should remain to it, already absolute*/ /* links need to remain absolute */ 0] '='#' ) { +strlen(newnaune)+strlen(oldname)+300+3 URLTrans(buffer,oldnaune, ULL,buf.anchor,sizebuf,sizeof(anchor) 1 , samedir = fsys_sa_me_dιr(bu .buffer1 | | ▼iβwsa β.c Tua Mar 21 10:24:14 1995 strcmp(fsys_naunetaιl(buf) ,buffer)==0; if ( pmatch!"application/x-navimap" ,guess_suffix(buffer) ; it buffer==fsys_naunetail(buffer) ) { /* Image map files should always be copied */ /* Image maps should always be local */ if ((ret = SaveMaplbuffer,oldname,newname,ctx->replacelιnkε ctx->doc,buf,sizebuf,ctx->already) )==- 1 ) { myfree(buffer) ; myfree(buf) ; return(0) , Cancelled */ ) /* If local, don't need to do a fix up in source */ /* unless we had to truncate the file name */ if I strcmp(buffer,fsys_naunetail(buf) ) !=0 ) { strcpy(anchor, εys_nametail(buf) ) ; HTML_FillTag(buf,tag) ; next = buf+HTML_HEAD_LEN; strcpy(next.tag==A_TAG?" HREF=" : " ACTION=" ) ; next += strlen(next) ; strcpy(next,anchor) ; next += strlen(next) ,- next = InsAttr(next,tagtext,taglen,tag,tag==A_TAG?"TITLE" : "METHOD" buf[HTML_LEN_LOW] = strlen(buf+HTML_HEAD_LEN)%256; buf[HTML_LEN_HIGH] = strlen(buf+HTML_HEAD_LEN1 /256; Replacelmage(page,para,tagtext,taglen,buf,HTML_HEAD_LEN+εtrlen(buf +HTML_HEAD_LEN) ,false) ) else if(ctx->replacelιnks || (isamedir tt !fsys_ιs_url (buffer) ) | | (samedir it fsys_badlιnkname(buffer,ctx->to) ) ) { HTML_FillTag(buf.tag) ; next = buf+HTML_HEAD_LEN; strcpy(nex ,tag==A_TAG?" HREF=" : " ACTION=' ) ; next = buf+HTML_HEAD_LEN; strcpy(nex , " HREF=") ; next += strlen(next1 ; if ( !ctx->replacelιnks it ! fsys_ιs_url(buffer) it fsys_badlιnkname(buffer,ctx->to) ) ( GenerateSaveName(buffer,oldnaune,newname,1, next,sizebuf- (next-buf) ,ctx->doc) ,- /* It is saunedir after all */ strcpy(next, fsys_nametaιl (next) ) ,- ) else URLTrans(buf er,oldname,NULL,next,anchor, sizebuf-(next-buf) .sizeof(anchor) 1 ; if ( anchor[0] !='\0' ) { strcat(next, *#*) ; strcat(next,anchor) ; ) next += strlen(next) ; next = InsAttr(next,tagtext,taglen,tag,tag==A_TAC"TITLE" "METHOD" ) buf[HTML_LEN_LOW] = εtrlenlbuf+HTML_HEAD_LEN)%256; buf[HTML_LEN_HIGH] = strlen(buf+HTML_HEAD_LEN)/256; Replacelmage(page,para,tagtext,taglen, buf,HTML_HEAD_LEN+strlen(buf+HTML_HEAD_LEN) .false) ; } myfree(buf) ; ) myfree(buffer) , return( 1 ), ) Run through the page, calling the given function on all the tagε */ ▼iawaava.c Tua Mar 21 10:24:14 1995 8 int XVT_CALLCONVl DoPageTaglterate (Page "page , int ( " func ) ( / * ??? * / ) , void "ctx , Selecti on *sel ) { Para 'para; int len , off ; char *pt , 'end; para = page-> irst; while ( para!=NULL ) { if ( sel==NULL || ρara->pnum >= sel->star .para->para->pnum ) { if ( ! ( func) (page,para,para->tag,para->tagtext?strlen(para->tagtext) :0, para->tagtext?para->tagtext: "",ctx) ) return(0) if ( para->text!=NULL ) { pt = para->text; end = pt+para->tlen; if ( sel!=NULL ) { if ( para->pnum == sel->end.para->para->pnum ) end = pt+sel->end.offset,- if ( para->pnum == sel->star .para->para->pnum 1 pt += sel->start.offset; ) while ( pt<end 1 { if ( *pt==HTML_MARK ) { len = ((unsigned char *)pt) [HTML_LEN_LOW]+ ((unsigned char *)pt) [HTML_LEN_HIGH] '256; off = pt-para->text; if ( ! (func) (page,para, ( (unsigned char *)pt) [HTML_POS_TAG] ,len, pt+4.ctx) ) return(0) pt = para->text+off; pt += Taglncr(pt); end = para->text+para->tlen; ) else ++pt; ) ) ) if ( sel!=NULL it para->pnum >= sel->end.para->para->pnum ) break; if ( para->fιrst!=NULL ) para = para->first; else { while ( para!=NULL it para->post==NULL ) para = para->parent; if ( para!=NULL ) para = para->post; ) ) return(1) ; ) Page *SaveAsHTML(Page 'page, char "naune, int saveimages, int replacelinks, int forced. Document 'doe, View 'view) ( char Oldurl = page->url ; struct saveasctx ctx; int rename = 0; Page "newpage; int freeneune = 0; int mailto = 0; Undo "base = page-.-undoes; page->saveasaltered = false; ▼iβwsa-ra.c Tua Mar 21 10:24:14 1995 9 if(pmatch!"mailto ", name)) ( rename = true, saveimages = 0, replacelinks = 0, mailto = 1; doc=NULL, ) else if ( fsys_urlcmp(name,page->url) '=0 ) { if(! forced) { /* It's a rename */ int ret = RESP_DEFAULT; if I PageLookup(name, "*,NULL) '=NULL ) { navι_dm_post_error(Vιewsave_AlreadyOpen /*"%.30s is already open, use a different name"*/.name) , if ( page->saveas ) return((Page *)0); /* Cancelled */ ret = RESP_2; } else if ( fsys_exιsts(name) ) { if (( ret=navι_dm_post_ask(General_Save/*"Save"*/, General_Rename/*"Rename"*/, General_DontSave/*"Dont Save"*/, Vιewsave_Exιsts/*"Fιle %.100ε already exists, save anyway'"*/, name) )==RESP_3 ) return) (Page *)0), /* Cancelled */ ) if ( ret==RESP_2 ) { if ((name = AskForName(name,doc))==NULL ) return((Page *)0), /* Cancelled */ freename = true, } } rename = true, ) newpage = (page->saveas ' page CopyPage(page) ) , if ( rename ) newpage->orιgurl = NULL; if ( doc==NULL ) { /* Check to see if this directory is a dociunent, and if so get the doc*/ /* info */ doc = DocFromFilename(name,view) , •if 0 /" We can't do this Users who set it are confused */ /* I hope it now defaults to a better value from the chooser */ ιf{ doc ) replacelinks = false, •endif ) if ( fsys_ιs_url (naune) tt 'fsys_ιs_url(page->url) ) { if ( replacel ks==l ) if ( xvt_dm_post_ask("Save", "Cancel" .NULL, "Can't generate full URLs for local files. Ok to leave linkε relative' " )==RESP_2 ; return((Page *)0), /* Cancelled */ replacelinks = false, ) else if ( replacelinks == -1 it doc ) replacelinks = false, else if ( replacelinks == -1 ) replacelinks = true, if ( page->base it (saveimages || replacelinks)) { oldurl = page->base; newpage->baεe = NULL, rename = true, /* if it haε a base then even if saving to the same place, it's effectively a rename as far as links go */ ▼iawsava . c Tua Mar 21 10:24:14 1995 10 } i f ( f sys_same_dιr ( oldurl , naune ) ) { if ( saveιmages==l ) saveιmages=0 ; replacelinks = 0; ) i f ( rename tt ( saveimages | | replacelinks | | doc) ) ( if ( ! orced tt page->style ' =NULL tt page->sheet ' =NULL ) { if ( SaveStl (page->sheet , oldurl , naune , saveimages , doc, page) == -1 ) return I I Page * ) 0) ; /* Cancelled * / ) ctx . saveimages = saveimages ; ctx. replacelinks = replacelinks ; ctx . oldurl = oldurl , ctx . newnaune = name, ctx . from = page->doc?page->doc->nametype :NauneTypeOf File (oldurl ) ctx. to = doc?doc->naunetype:NauneTypeOfFιle (naune) , ctx . doc = doc; ctx.already = NewFor lname, NULL, 0) ; DoPageTagl erate(newpage,pupdateimages,tctx,NULL) ; DelForm(ctx.already) ; if ( page->saveasaltered ) UndoAddMultiple(page, false,base) ; ) PageSave (newpage,name, /* Generate a Base if... */ mailto I | (!saveimages it 1replacelinks tt doc==NULL it rename tt ■ ' fsys_same_dιr(oldurl,naune) it 'forced), false,view, false) ; return(newpage) ; ) •if XVT_OS_ISUNIX •define EOL "\n" •elif XVT_OS_IS_WINOS •define EOL "\r\n" •else •define EOL "\r" •endif static char 'TagText (char *pt, char 'buffer, mt size) ( if { HTML_tag(pt)==IMG_TAG ) { if ( !HTML_HasAttr(pt,buffer,size, "ALT") ) return( "<Image>" ),- return! buffer ) ; } else if ( HTML_tag(pt)==INPUT_TAG ) { if ( !HTML_HasAttr(pt,buffer, size, "TYPE") ) strcpy(buffer, "text" ) ,- if ( strmatch(buffer, "submit" )==0 ) { if ( !HTML_HasAttr (pt,buffer+1,size "VALUE") ) strcpyfbuffer+1, "Submit" ) ; buffer[0] = * [ ' ; strcat (buffer, "]"),- ) else if ( strmatch(buffer, "reset" )==0 ) { if ( !HTML_HasAttr(pt.buffer+1,size "VALUE") ) strcpy(buffer+1, "Reset") ,- buffer [0]= ' [ ' ; strcat (buffer, "]"),- ) else if ( strmatchlbuffer, "radio" )==0 ) { return ( "<>" ) ; } else if ( strmatch(buffer, "checkbox" ) - ~~~ ~ ) { return("[]"); ) else if ( strmatch(buffer, "checkbox" )==0 ) { ▼iβwaava.c Tua Mar 21 10:24:14 1995 11 return( "[Image]" ) ; } else return ( " [ ] " ) ,- ) else if ( HTML_tag(p ) ==SELECT_TAG ) return! " [ ]v" ) ; else if ( HTML_tag(pt)==TEXTAREA_TAG > return! "[ ]" ) ; else if ( HTML_tag(pt)==HR_TAG ) return! "\t return( " " ) ; ) static void XVT_CALLCONVl SaveTextParagraphlFILE "fp, VPara "vpara, View "view) ( VPara *vp; char buffer (200) ; char *pt, *word_start; int i, indent, subind, ind, wi; int hres = vιew->hres; if ( vpara->subs ! =NULL ) { for I vp = vpara->subs; vp!=NULL, vp=vp->poεt ) SaveTextParagraph(fρ,vp,vιew) ,- ) else if ( ParaPreformatted! vpara->para )) ( fputs (EOL, fp) ; for ( pt = vpara->para->text; "pt; ) ( if ( *pt==HTML__MARK ti TagHasWidthlpt11 { if ( HTML_tag(pt)==HR_TAG | | HTML_tag(pt1==BR_TAG 1 fputs(E0L, fp) ; fputs (TagText (pt,buffer,sizeof (buffer) ) , fp) ; if ( HTML_tag(pt)==HR_TAG ) fputs (EOL, fp) ; ) else if ( *pt==HTML_MARK ) /* Do Nothing */ ; else if ( *pt=='\n' ) fputs (EOL, fp) ; else fputc ("pt, fp) ; pt += Taglncr (pt) ,- ) fputs (EOL, fp) ; } else { indent = (vpara->indent*72/hres) /5; assume average char = 5 points subind = (vpara->submd*72/hres) /5; fprintf ( fp, EOL ) ; for ( pt = vpara->para->text; *pt.'='\0'; ) { for ( i=0; ι<indent; ++ι ) lιne[i]= ' while ( *pt ) { word_start = pt; wi = i; if ( *pt==HTML_MARK ii TagKasWidth(pt) ) { word_start = TagText (pt.buffer.sizeof (buffer) 1 ,- if ( ι==ιndent it ι+strlen(word_start) >=sιzeof (line) - 1 ) word_start(sizeof(line) -2-ιndent] = ' \0',- if ( ι+strlen(word_start)<sizeof (line) -1 tt HTML_tag(pt) !=HR_TAG it HTML_tag(p 1 !=BR_TAG) pt += Taglncr(pt) ; strcpy(1ιne+i,word_start) ,- l += strlen(line+i) ,- ) else break; } else { while !navι_ιsspace(*pt) ti ! ( *pt==HTML_MARK ii TagHasWidth(pt) ) it • pt'='\0' ) ( if ( ι==sιzeof (line) -1 ) { ▼iawaava.c Tua Mar 21 10:24:14 1995 12 if ( wι.'=mdent ) { pt = word_start,- I = wi; } brea ; } if ( *pt!=HTML_MARK ) lme[i++] = *pt++; else pt += Taglncr(pt) ; ) ) while ( navi_ιsspace( *pt ) || Cpt==HTML_MARK it 'TagHasWιdth(pt) 1 ) pt += Taglncr(pt); if ( i>=sιzeof(line)-2 ) break; line[ι++]=' ' ; ) if ( lιne[i-l]==' ' ) --i ; lιne[i]='\0'; if ( vpara->just!=J_Filled || *pt=='\0' ) ( ind = 0; if ( vpara->just==J_Center ) ind = (sizeo (line)-l-i)/2; ; t wc, ew, extra; char *wpt; wc = 0; for ( wpt = lιne+indent; *wpt; ++wpt ) if ( *wpt==' ' ) ++wc; ind = (sizeof(line)-l-i) ; ew = ind/wc; extra = ind-ew'wc; for ( ind = 0; md<ιndent; ++ιnd ) fputc( ' ' ,fp) ; for ( wpt=lιne+mdent; *wpt; ++wpt ) { fputc(*pt,fp) ; if ( *pt==' ' ) { for ( ind = 0; ιnd<ew, ++ιnd ) fputc( ' ' , fp) ; if ( extra ) { fputc(' ' ,fp) ,- —extra; ) } ♦+pt; ) ) fputs{EOL, p) ; if ( HTML_tag(pt)==BR_TAG ) pt += Taglncr(pt); else if ( HTML_tag(pt)==HR_TAG ) { fputs(TagText(pt,buffer,sizeof(buffer) ) , fp) ,- fputs(EOL, p) ; pt += Taglncr(pt) ,- ) indent = subind; . ) ) static void XVT CALLCONVl ViewSaveAsFormattedText(View 'view, char 'name) { -riewsa-a.c Tua Mar 21 10:24:14 1995 13 FILE 'fp; VPara 'vpara; fp = fopen(name, "w") ; if ( fp=«NULL 1 { /' We know we have write access, how can this happen' */ navι_dm_post_error(Vιewsave_NoWrιte/*"No write access to %.100s"*/, name ) ; return; ) for ( vpara = vιew->fιrst; vpara'"NULL; vpara=vpara->post) SaveTextParagraph(fp,vpara,view) ,- fclose(fp) , ) static void XVT_CAL1_C0NV1 V ewSaveAsText(View 'view, char 'name, mt linebreaks) { Para 'para = view->page->firsft; FILE *fp; char *pt; fp = fopenlnaune, "w") ; if ( fp==NULL ) { /' We know we have write access, how can this happen' */ navι_dm_post_error(Vιewsave_NoWrιte/*"No write accesε to %.100ε"*/, name ), return, } while ( para'=NULL ) { pt = para->text; if ( pt'=NULL ) { while ( 'pt'='\0' ) { if { HTML_tag(pt)==HR_TAG ) fprintf(fp, "%s\t %s" ,E OL.EOL) ; else if ( *pt==HTML_MARK ) pt += Taglncr(pt); else if ( navι_ιsspace(*pt) ) { while ( navι_ιsspace(*pt) || *pt==HTML_MARK ) pt += Taglncr(pt) , fputc(' '.fp); ) else { fputc(*pt,fp) , ++pt, ) ) fprint (fp,EOL) ; } if ( para->fιrst'=NULL ) para = para-> rst; else { while ( para!=NULL tt para->post==NULL ) para = para->parent; if ( para'-NULL ) para = para->post; ) ) close!fp) , ) static int outchrlvoid 'vctx,int ch) ( FILE *fp = vctx; return)fputc(ch, fp) ) ; ) static void XVT_CALLCONVl ViewSaveAsFilter(View 'view, char 'name, char *cmd) { •if XVT OS ISUNIX viβwβa-a.c Tua Mar 21 10:24:14 1995 14 extern int system(const char *) ,- char buffer[2000] , tmp(lOO), *pt; FILE *fp; extern char 'mytmpna (char *) ; pt = mytrπpnam(tmp) ; fp = fopenfpt, "w") ; WritePage(view->page,true,outchr, (void *)fp); fclose(fp) ; sprintf( buffer, "(%s %s %s ; rm %s ) i", cmd, pt, name, pt ); system! buffer ); •else IError("Filtered SaveAs NotYe Implemented") ; /* ! ! ! ! */ •endif ) static struct exttype { char *type; char *cmd; } fltrtabU = { (char *)0, (char *)0); static int freeable=0; static struct exttype 'fltrpt = fltrtab; struct exttype 'savefilter_mappings(void) { return) fltrpt ) ,- ) void set_savefilter_mappings(struct exttype 'newmap) { int i; if ( freeable ) { for ( i=0; fltrpt[i] .type!=NULL; ++i ) { myfree{fltrpt[i] .type) ; myfree(fltrpt[i] .cmd) ,- ) myfree(fltrpt) ; ) fltrpt = newmap; freeable = 1; ) /* void XVT_CALLCONVl SaveAsChangeType(WINDOW w) { ) void XVT_CALLCONVl SaveAsNameChange(WINDOW w) { } void XVT_CALLCONVl SaveAsFiHup(WINDOW w) { } void XVT_CALLCONVl SaveAsSave(WINDOW w) { } */ void XVT_CALLCONVl ViewSavelnto(WINDOW w) { xvt_scr_beep() ; ) static int SaveAsOkfvoid *ctx, char *url, struct chooserinfo 'info) { View 'view = (View *) ctx; int sel = info->_as_type; int ret = true; Document *doc; navi_set_dlg_wait_cursor(info->w) ; doc = DocFromFilename(url, (View *) (info->ctx) ) ,- ▼iawaa-a .c Tua Mar 21 10 :24 : 14 1995 15 navι_set_dlg_norm_cursor ( inf o->w) ,- if ( fsys_badname (url , oc?doc->nametype : fn_local ) 1 { navi_dm__>ost_error (Attrdlg_BadName ) ; fsys_makegoodname (url , oc?doc- >nametype : fn_local ) ; xvt_vobj_set_tιtle (xvt_wm_get_ctl ( inf o->w, FιleChs_URL) , url ) ; ChooserSetSel(mfo->w) ; return 0; ) /* SaveAsHTML does this check, so don't if sel==0. We need to do it there*/ /* because t gets called individually, we need to do it here for all the*/ /* other cases */ if ( sel!=0 ti url_exιsts(url) ) { if ( navι_dm_post_ask(General_Save/*"Save"*/, General_Cancel/*"Cancel"*/,NULL_RID, Vιewsave_Exιsts/*"Fιle %.100s already exists, save anyway'"*/, url) '-RESP_DEFAULT ) return 0; ) switchIsel) { case 0 if( 'pmatch!"mailto: " ,url) ) vιew->page->saveas = true, i !'SaveAsHTML(view->page,ur1, ιnfo->saveιmages,info->fullurlobserved?ιnfo->fullurl:-1, false, NULL.view)) ret = false; vιew->page->saveas = false; break; case 1: ViewSaveAsTextIview,url,1) ; break; case 2: ViewSaveAsFormattedText(view,url) , break; •if XVT_OS_ISUNIX case 3: ViewSaveAsPostscπpt(view,url) ; break; default sel -= 3, •elεe default- sel -= 2; •endif ViewSaveAsFilter(view,url,fltrpt[sel] .cmd) ; break; ) return ret; ) void XVT_CALLC0NV1 PageSaveAs(Page "page, View "view) ( char buf[0x200] , *pt; View "old; /* The view may not be active, but it should provide us with the context */ /* we need none the lesε */ if ( vιew=«NULL ) view = page->vιews, if ( vιew==NULL ) { IError("No view in PageSaveAs"); return, ) ▼iawaa-a.c Tua Mar 21 10:24:14 1995 16 if ( (View *) xvt_vobj_get_data(view->w)==view tt view->page==page 1 xvt_vob _get_title(xvt_win_get_ctl(view->w,Page_URL) ,buf,sizeof(buf) ) ,- else strcpylbuf, page->url) ,- fsys_makerealname(buf,bu +strlen(buf) .εizeof(buf)-εtrlen(buf) , fn_local) ; pt = strrchr(fsys_nametail(buf) , '.'),- if ( pt»=NULL ) pt = buf+strlen(buf) ; if ( !pmatch!"text/html" ,guess_εuffix(buf) ) ) •if XVT_OS_IS_WINOS strcpy(pt, " .htm") ; •else strcpy(pt, " .html") ; •endif old = (View *)xvt_vobj_get_data(view->w) ,- xvt_vobj_set_data(view->w, (long) view); xvt_vobj_set_data(view->pane, (long) view) ; Chooselt(view,Viewcmd_Saveas,buf.sizeof(buf) ,CHOOSER_SAVEPG,SaveAsOk) ; xvt_vobj_set_data(view->w, (long) old) ; xvt_vobj_set_data(view->pane, (long) old); ) void XVT_CALLCONVl ViewSaveAs(WINDOW w) { View "view = (View *) xvt_vobj_get_data(w) ; PageSaveAs(view->page,view) ; } void XVT_CALLC0NV1 ViewSave(WINDOW w) { View "view = (View *) xvt_vobj_get_data(w) ; Page 'page = view->page; if ( page->noname ) PageSaveAs(page,view) ,- else PageSave(page, page->url, false, false,view,false) ; ) ▼iawαad.c Fri Mar 24 13:23:48 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved. */ •include <xvt.h> •include "keymore.h" •include "NaviPres.h" •include "func.h" •include "ht l.h" •include "view.h" •include "undo.h" •include "style.h" •include "doc.h" •include "callback.h" •include "guess.h" •include "crud.h" •include "chooser.h" •include "str.h" «, •include "nεdefε.h" •include "memmask.h" •include "callback.h" •include "xlocal.h" static void _UndoIt PROTOTYPE! (View *,Undo ",ιnt)), static void Undolt PROTOTYPE* (View *,mt)), int XVT_CALLC0NV1 ViewReadOnly(View "view) { int ret; int was_protected = false, int was_grabbed = vιew->panetrapped; vιew->panetrapped = false, if ( vιew->page->frozen ) { navι_dm_poεt_warnιng(Vιewcmd_TempLock/*"Thιε page lε temporarily locked, you may n ot change it now"*/); ret = true; ) else if ( vιew->page->orthodata ) { xvt_wιn_release_poιnter() ; xvt_dm_post_warnιng("You may not modify th s page"), ret = true; ) else if ( vιew->page->modιfyable ) ret = false; else if ( navι_dm_post_ask(Vιewcmd_Change/*"Change"*/,Vιewcmd_Protect/*"Protect"*/,NUL L_RID, Vιewcmd_RO/*"Thιs page may not be saved, do you still want to change ιt'"*/)== RESP_DEFAULT ) { vιew->page->modιfyable = true; VιewSelectιonHasChanged(vιew) ,- /" It hasn't but our interpretation may have */ /* Whether to show form element dialogue.. */ ViewSetCursor(view) ; /* Change to l-beaun for text insert */ ret = false, was_protected = true; ) else ret = true; if ( !ret it vιew->wιnfo->source'=NULL_WIN ) xvt_vobj_destroy(vιew->wιnfo->source) , if ( ret I I was_protected ) { vιew->mouse_down = false; if ( vιew->drag_and_drop ) ( vιew->drag_and_drop = false, if ( vιew->drag_marque ) ViewDrawDragMarque(view,view->laεtdrag.h,vιew->laεtdrag.v) , ViewSetCursor(view) ,- } ) if ( !ret ) viawcβd.c rri Mar 24 13:23:48 1995 2 vιew->panetrapped = was_grabbed, return( ret ) , ) void XVT_CALLC0NV1 Ex tApp (vo d) { apρ_exιt{) , } void XVT_CALLC0NV1 ViewClose(WINDOW w) { View "view = (View *) xvt_vob3_get_data(w) , mt anyothers; xvt_scr_set_busy_cursor{) ,- while ( vιew->fore'=NULL ) view = vιew->fore, for ( vs=vιew, vs'=NULL, vs=vs->back ) CrudForVιew(vε,abort_get,NULL) ; /* Abort outstanding requests */ vs = view; NPCrudRundown() , /* wait for saves, etc to finish */ while ( view'-NULL ) ( next = vιew->back, anyothers = false, for ( vs=vιew->page->vιews, vs'=NULL, vs=vs->nextsame ) if ( vs->w'=w ) anyothers = true; if ( !anyothers ) { /* Last window looking at this page */ if( 'PageCommit(vιew->page,view) ) return, /* cancelled */ ) view = next, ) NPCrudRundown() ; /* wait for saves, etc to finish */ /* Then check that they succeded */ next = vιew->back, anyothers = false; for ( vs=vιew->page->vιews, vs'=NULL, vs=vs->nextsame ) f ( vs->w'=w ) anyothers = true, if ( !anyothers ) { i ( vιew->page->changed || 'vιew->page->savesucceded ) { /* Save failed if ( vιew'=(View ♦ ) xvt_vob3_get_data(w) ) { ViewSetupFree(view,w, (View *) xvt_vob3_get_data(w) ) , VιewRedraw(vιew) , ) xvt_dm_ρost_message("Save Failed' ") ; return; } ) if(ValιdVιewWιndow(w) ) /* may already be dead xvt_vob3_destroy(w) , ) /* Called when the cursor moves in a page when a mouse button is not depressed */ /* de when we aren't selecting, but are looking for links to display) */ void XVT_CALLCONVl VιewCheckMouse(Vιew "view, EVENT "event) { register int x=event->v. ouse.where.h+vιew->text__of left, y-event->v.mouse.where.v+view->text_of top, register LinkList "Ink, "end; char buffer[100] ,- if ( (Ink = vιew->lιnk_under_cursor) '=NULL ) { ▼iawead.c Fri Mar 24 13:23:48 1995 3 if ( x>=lnk->pos . lef tt x<=lnk->pos . right tt y>=lnk->pos . top it y<=lnk->pos . bottom ) { /* Current link is still valid, current message still good * / return ; } } for ( lnk=view->links, end=lnk+vιew->lcn ; lnk<end; ++lnk ) ( /* This list is not ordered */ if ( y<=lnk->pos.bottom ii y>=lnk->pos.top it x>=lnk->pos.left it x<=lnk->pos.right ) break; } if ( lnk==end ) lnk=NULL; if ( lnk==NULL it vιew->lmk_under_cursor==NULL ) ( /" No change, nothing interesting, unless we went outside the window */ if ( vιew->pendιng ) { RCT ret; xvt_vob3_get_outer_rect(vιew->w,irct1 ,- xvt_vobj_translate_poιnts(vιew->pane,SCREEN_WIN,tevent->v.mouse.where,1) , x = event->v,mouse.where.h, y = event->v.mouse.where.v, if ( vιew->lιnkshown '= ( x<rct.left || x>rct right | | y<rct top || y>rct.bottom )) ( f ( 'vιew->lιnkshown ) { xvt_res_get_str(Vιew_FollowLmk,buffer,sizeof(buffer) ) , /*"follow link .."*/ strncat(buffer, vιew->pendmg, sizeof(buffer)-20) , ViewSetMessage(view,buffer) ; ) else VιewStdMsg(vιew) , vιew->lιnkshown = 'vιew->lιnkshown; ViewSetCursor(v ew) ; ) } ) else if ( lnk==NULL ) { vιew->lιnk_under_cursor = NULL; ViewSetCursor(view) ; ViewStdMsg(view) ,- } else if ( vιew->pendιng it strcmp(lnk->naune,vιew->pendιng) '=0 ) { vιew->lιnk_under_cursor = NULL; ViewStdMsg(view) , } else ( vιew->lιnk_under_cursor = Ink; ViewSetCursor(view) ; xvt_res_get_str(Vιew_FollowLιnk,buffer,sizeof(buffer) ) ;/*"follow link "*/ strncat(buffer, lnk->oπgname, sizeof(buffer)-20) ; ViewSetMessage(view,buffer) ; ) } void XVT_CALLCONVl V ewAlterURL(Vιew "view. Page "page) ( View *nv; if( 'view) { CreatePageWm(page) ; return; ) nv = newVιew(page) ; VιewAd3UstBackFore(nv,view) ,- nv->truepane = nv->pane = vιew->pane; nv->stat = vιew->stat, ViewSetupFreelnv,vιew->w,v ew) , ▼iawcβd.c Fri Mar 24 13:23:48 1995 4 VField 'SearchForImage(VPara 'vpara, long int x, long t y) { while(vpara) { VField *vf, int i; ford = 0; l < vpara->fcnt; ++) { if(vpara->fields[i] .ismap) { vf = vpara->fιelds+ι; if(vf->x < x ii vf->x+vf->wιdth > x ii vf->y < y ti vf->y+vf->heιght > y) return vf, ) ) ιf((vf = SearchForImage(vpara->subs, x, y) ) ) return vf; vpara = vpara->post, ) return (VField *)0; /* Called on a release if we want to follow a link (link in lιnk_under_cursor) */ /* If this is a double click then create a new window If a single then */ /* start reading the page n, and send out a timer interrupt If we get the */ /* timer before another click then change the current page */ void XVT_CALLC0NV1 ViewLin (View "v ew, t x, int y) { View "newview = NULL; Form "form, struct crud 'crud; View 'forwards = NULL; if ( vιew->lιnk_under_cursor'= NULL tt vιew->lιnk_under_cursor->ιmage ) { Image *image; /* An image load was aborted, or never started Initiate it now */ if (( image = ImageLookupl iew->pendιng, "".NULL) )'=NULL ) { myfree(vιew->pendιng) ; vιew->pendιng = (char *)0, ImageReadm(image,view,false) , return, } } / • did we drag outside the window' */ /* if so, create a new PageWin... */ newview = view; if ( view->press_pnt.h'=x+vιew->text_offief || vιew->press_pnt.v!=y+vιew->text_offtop ) { PNT from, from.h = x; fro .v = y; xvt_vobj_translate_poιnts(vιew->pane,SCREEN_WIN,tfrom,1) , newview = ViewW FindViewtview,from.h,from.v) , ) if ( newvιew==vιew it vιew->lιnk_under_cursor==NULL ) { myfree(view->pendιng) ; vιew->pendιng=NULL; return; ) /* Abort any communication which plans to draw into this window */ if ( newview'-NULL ) CrudForView(newview,abort_get_local, ULL) , forwards = vιew->fore, /* save these to be dealt with later */ vιew->fore = NULL; /* Can't delete until we get a double click */ if ( forwards'=NULL ) forwards->back = NULL, ) ▼iawαad.c Fri Mar 24 13:23 :48 1995 5 /* was this a clicked image' * / { long x = vιew->press_pnt . h; long y = vιew->press_pn . v; VField "vf = SearchForImage (vιew->fιrεt , x, y) , ιf (vf ) { char buf[0x10] ; X -= vf->x; y -= vf-->y; sprintf(buf, "%ld,%ld", x, y) ; form = NewForm("GET" , vιew->pendmg, 1); AppendFormField(form, NULL, buf, 0, 0); crud = SubmιtForm(form, view, vιew->page->url) , ) else if ( newview '= NULL tt newvιew->tag==TAG_DOCUMENT ) { DocAddPageName( ( (DocView *) newview)->doc,vιew->pendιng, -1,-1) , crud = NULL, ) else { crud = OpenURL(view->pendιng, OPEN_DEFAULT, false,view->page->url) , } vιew->pendιng = (char *)0, if ( newvιew==vιew ) ( vιew->wιnfo->pendmg_context = (crud==NULL)' NULL • crud->ctx; vιew->wιnfo->lιnkchangιng = true; vιew->wιnfo->pendιng_forwards = forwardε, vιew->wιnfo->pendιng_ιd = xvt_tιmer_create(vιew->pane, (long) CLICKTIME) , vιew->wιnfo->reεtore_vιew = view, ViewSetCursor(view) ,- ) ) ) /* Called if they double-clicked on a link */ /* There are all sorts of complications here The link may already be shown */ /* • in the window, n which case we must get rid of it and put it into a new */ /* window */ void XVT_CALLC0NV1 VιewLιnkToNewW ndow(Vιew "view) { Page "page, View " forwards = vιew->wιnfo->pendmg_f orwards , vιew->wιnfo->pendιng_f orwards = NULL, xvt_tιmer_destroy(vιew->wιnfo->ρendιng_ιd) , vιew->wιnfo->pendmg_ιd = 0 ; if ( vιew->wmfo->pendιng_context ' = NULL ) { /* This is the easy part , the link has not shown up * / vιew->w nfo->pendιng_context->newvιew = true; } else if ( vιew->wιnfo->restore_vιew ' =NULL tt vιew==vιew->wιnfo->restore_vιew->fore ) { / * The thing is already in the window, abort any cruds to load images * / / * (which would be confused by having their window change beneath ' eir* / CrudForVιew(vιew, abort_get , NULL) ; page = vιew->page; VιewBack (vιew->w) ,- view = vιew->wιnfo->restore_vιew, ViewFreeList (vιew->fore , false) ; ViewSetMenu (view, true) ; CreatePageWm (page) ; ) else if ( vιew->wmfo->restore_vιew==vιew ) { * Link to the saune page */ page = vιew->page, CreatePageWin (page) ; ) else { ViewClearPendinglnf o (vιew) , ▼iewcβd.c Fri Mar 24 13 :23 :48 1995 6 return, / * Su pun screwed up * / ) vιew->fore = forwards, if ( forwards'=NULL ) forwards->back = view; vιew->wιnfo->pendιng_context = NULL, vιew->wιnfo->pendιng_forwards = NULL; vιew->wιnfo->lιnkchangιng = false, vιew->wιnfo->restore_vιew = NULL; ViewSetCursor(view) ,- ViewSetupURLs(view) ; ) void ViewClearPendinglnfo(View 'view) { if ( vιew->wιnfo->pendιng_ιd'=0 ) xvt_tιmer_destroy(vιew->wιnfo->pendmg_ιd) , vιew->wιnfo->pendιng_ιd = 0, vιew->wιnfo->pendιng_context = NULL, vιew->wιnfo->lιnkchangιng = false, ViewFreeList( iew->wιnfo->pendmg_forwards,false) , vιew->wιnfo->pendmg_forwards = NULL, vιew->wιnfo->restore_vιew = NULL, ViewSetCursor(view) ,- ) void XVT_CALLCONVl ViewUp(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) , Page 'page = vιew->page; if I page->upl==NULL | | page->frozen ) xvt_scr_beepI) , else ViewAlterURL(view,newPage(page->upl, age->ur1,page->base,page->uptιt) ) ) void XVT_CALLC0NV1 ViewHome(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) , extern char 'home_page; ViewAlterURL(view,newPage(home_page, "".NULL,NULL) ) , ) void XVT_CALLC0NV1 ViewBack(WINDOW w) { View 'view = (View *) xvt_vob _get_data(w) ; if ( vιew->back!=NULL tt 'vιew->page->frozen ) { VιewSetupFree(vιew->back,view->w,view) , VιewRedraw(vιew) ,- } else xvt_scr_beep() ; ) void XVT_CALLC0NV1 ViewForeward(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) , if ( vιew->fore'=NULL it 'vιew->page->frozen ) { ViewSetupFree(vιew->fore,vιew->w,view) ; VιewRedraw(vιew) , } else xvt_scr_beep() ; ) void XVT_CALLC0NV1 ViewBookmark(WINDOW w, mt mark) { View "view = (View *) xvt_vob _get_data(w) , c Fri Mar 24 13 : 23 :48 1995 long pos ; f ( mark>=vιew->acnt ) xvt_scr_beep ( ) ; else { pos = view- >anchors [mark] . y-52 ; if ( poε<0 ) poε = 0 ; ViewSetVScroll(view,pos ) ,- ) } void XVT_CALLC0NV1 ViewScrollToBookmark(WINDOW w, char 'name) { View 'view = (View *) xvt_vob _get_data(w) ,- for ( ι=0; κvιew->acnt; ++ι ) if ( strmatch(vιew->anchors[i] .naune,name)==0 ) { ViewBookmark(w,i) ; return; ) ) static int inlist(char *url,char "urls.mt cnt) { t 1; for ( i=0, ι<cnt; ++ι ) if ( strcmp(url,urls[1] )==0 ) return true; return false; ) void XVT_CALLC0NV1 ViewReloadCurrent(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) ; VPara *vp; char "urls=NULL; mt cnt=0, tot=0; if ( vιew->wmfo->source'=NULL_WIN ) xvt_vobj_destroy(vιew->wιnfo->source) ,- f ( vιew->page->frozen it VιewReadOnly(vιew) ) return; if ( vιew->page->changed it xvt_dm_post_ask("Reload", "Cancel", NULL, "Reloading will lose your changes. Reload anyway?")==RESP_2 ) return; if ( ( view->page->noname | | view->page->new ) tt !url_exιsts(vιew->page->url) ) { /'A reload will give us a "Page not found" 'cause it hasn't been saved* /* but we should blank out the thing... */ ViewSelectAll(view) ; ViewChangelview, "",0,false. alse) ; UndoFree(view->page->undoes) ; UndoFree(vιew->page->redoes) , xvt_menu_set_ιtem_enabled(vιew->w,PageMenu_Redo,false) ; xvt_menu_set_ιtem_enabled(vιew->w,All_Undo,false) ; vιew->page->undoeε = NULL; vιew->page->redoeε = NULL; PageSetChanged(vιew->page,false) , return; } CacheFlush(vιew->page->url) ; viewc-βd.c Fri Mar 24 13:23:48 1995 8 UndoFree(vιew->page->undoes) ,- UndoFree(view->page->redoes) ; xvt_menu_set_ιtem_enabled(vιew->w,PageMenu_Redo, false) ; xvt_menu_set_ιtem_enabled(view->w.All_Undo, alse) ; vιew->page->undoes = NULL; vιew->page->redoes = NULL; PageSetChanged(vιew->page,false) ; vιew->page->readstarted = false; ViewStdMsg(view) ; ViewsSaveSel(vιew->page) ; VParaFreeL st(vιew->first, false) ,- vιew->fιrst = NULL; ReloadURL(vιew->page->url, view, NULL); NPCrudRundown() ; /'Get the view in good shape before we put pictures in it */ vp = vιew->fιrst; while ( vp'=NULL ) { for ( ι=0; κvp->fcnt; ++ι ) if ( vp->fιeldε[i] .type = - f_ιmage || vp->fields[i] .type == f_ιmagefιeld ) { if ( !inlist(vp->fields[l] .ιmage->url,urls,cnt) ) { CacheFlush(vp->fields[i] .ιmage->url) ; ReloadURL(vp->fields(i] .ιmage->url, view, vp->fields[I].image) ,- if ( cnt>=tot ) urls = (char **) myrealloc(urls, (tot+=10)'εizeof(char*)) ; urls[cnt++] = vp-_»fields[I] .ιmage->url; } } if ( vp->subs!=NULL ) vp = vp->subs; else { while ( vp!=NULL ii vp->post==NULL ) vp = vp->parent; if ( vp!=NULL ) vp = vp->post; ) ) myfree(urls) ; ) void XVT_CALLC0NV1 ViewReloadGlobal(WINDOW w) { View 'view = (View *) xvt_vob3_get_data(w) ,- VPara *vp; int l; int cnt=0, tot=0, went; t spn, soff, epn, eoff; WINDOW 'wins; ImageCachePurge() ; PageFlushCache() ; wins = WιndowHead(twcnt) ; for ( ι=0; i<wcnt; ++ι ) { view = (View *) xvt_vobj_get_data(wins[l] ) ; spn = soff = epn = eoff = 0; if ( vιew->sel.start.none ) { spn = epn = vιew->caret.para->para->pnum; soff = eoff = vιew->caret.offset; } else { spn = vιew->sel.star .para->para->pnum; soff = vιew->sel.start.offset; epn = vιew->sel.end.para->para->pnum; eoff = vιew->sel.end.offset; ) if ( vιew->page->changed 1 ▼iβwβad.c Fri Mar 24 13:23:48 1995 9 CacheFlush(vιew->page->url) ; ReloadURL(vιew->page->url, view, NULL), if ( vιew->wιnfo->source!=NULL_WIN ) xvt_vobj_destroy(vιew->w nfo->source) ; UndoFree(view->page->undoes) ; UndoFree(view->page->redoes) , xvt_menu_set_ιtem_enabled(vιew->w,PageMenu_Redo, falεe) , xvt_menu_set_ιtem_enabled(vιew->w,All_Undo,false) ; vιew->page->undoes = NULL; vιew->page->redoes = NULL; PageSetChanged(vιew->page,false) , ViewStdMsg(view) ; vp = vιew-> ιrst; while ( vp!=NULL ) { for ( ι=0; κvp->fcnt; ++ι ) if ( vp->fιelds[ι] .type == f_ιmage || vp->fields[I] type == f_ιmagefιeld { if ( !inlist(vp->fields[I] .ιmage->url,urls,cnt) ) { ReloadURL(vp->fields[i] ιmage->url, view, vp->fields[I] image), if ( cnt>=tot ) urls = (char **) myrealloc(urls, (tot+=10) "sizeof (char*) ) , urls[cnt++] = vp->fields[l] .ιmage->url, } ) if ( vp->subs!=NULL ) vp = vp->subs; else { while ( vp'=NULL tt vp->post==NULL ) vp = vp->parent; if I vp'=NULL ) vp = vp->post; ) ) ViewShowSelection(view,spn,soff,epn,eoff) ,- ) myfree(urls) ; ) void XVT_CALLC0NV1 ViewPasteField(WINDOW focus,int istitle) { int first, last; long len; char buffer(400], bu er2 [500] ; char *str; lf ( xvt_cb_open(false) ) { if (( str=xvt_cb_get_data(CB_APPL, "LINK",tlen) ) •=NULL ) { if ( istitle ) xvt_vobj_set_tιtle(focus,str) ,- else xvt_vob _set_tιtle(focus,str+strlen(str)+1) ; xvt_cb_close() ; return, ) else if (( str * xvt_cb_get_data(CB_TEXT,NULL,tlen) )'=NULL ) { str = copylstr) ; len = strlen(str); ) else { str = copy!"") ; len = 0; } xvt_cb_closeI) ; ) xvt_ctl_get_text_selIfocus,ifirst,ilast) ,- xvt_vob _get_titieIfocuε,buffer,εizeof(buffer) ) ; strncpy(bu fer ,buffer,first) ; if ( len+first >= sizeof(buffer2) ) len = sizeof(buffer2) -fιrst-1; ▼iaweαd.c Fri Mar 24 13:23:48 1995 10 strncpy(buffer2+first,str,len) ; if { fιrst+len+strlen(buf er+last)>=sιzeof(buffer2) ) buffer[last+sizeof(buffer2)-fιrst-len)='\0' , strcpy(buffer2+first+len,buf er+last) ; xvt_vob _set_tιtle(focus,buffer2) ; ) void XVT_CALLC0NV1 ViewPaste(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) char *str, 'title, *url; long len; WINDOW focus; if I! focus=xvt_scr_get_focus_vob () ) '=vιew->pane ) ( vιew->w,Page_Tιtle) ) retu } ) if I ViewReadOnly(view) ) return. if ( xvt_cb_open(false) ) { if (( str=xvt_cb_get_data(CB_APPL, "HTML",tlen) ) '=NULL ) { str = copyn(str,len = HTML_len(str) ) ; /* Make sure there are no HTML MARKS in str */ } else if (( str=xvt_cb_get_data(CB_APPL "LINK",tlen) ) '=NULL ) title = copylstr) ; url = copy(str+strlen(tιtle)+l) , ViewApplyLink(view,url,title,NULL) , xvt_cb_close() ; my reeItitle) ; myfree(url) , return; ) else if ( ( str=xvt_cb_get_data(CB_TEXT,NULL,tlen) ) =NULL ) { str = copylstr) , len = strlen(str) ; else { str = copy(" ') ; len = 0; ) xvt_cb_close() , VιewChange(vιew,str,len, false,false) , myfree(str) ; ) else xvt_scr_beep() ; ) static mt XVT_CALLC0NV1 _VιewCopy(WINDOW w) { View 'view = (View *) xvt_vob3_get_data(w) , char "sel = NULL; char 'selcopy, *ptl, *pt2; WINDOW focus, char buffer[400] , if (( focus=xvt_scr_get_focus_vob3 () ) '=vιew->pane ) ( int type = xvt_vob3_get_type(focus1 ; if ( type==WC_EDIT | | type«WC_LISTEDIT ) { int first, last, xvt_vob3_get_tltie(focus,buffer,sizeof(buffer) ) , xvt_ctl_get_text_sel(focus,tfirst,tlast) ,- buffer[last]='\0' ; Fri Mar 24 13:23:48 1995 11 sel = buf er+first; /* There was a return here, should not have been, should fall */ /* code below to do actual copy */ } else focus = NULL_WIN; } else focus = NULL_WIN; if I focus'=NULL_WIN ) ( /* Noop •/; ♦ifdef MEMORY_MASK } else if ( IsSelectιon2HtmlTooLong(vιew,tvιew->εel,true,MEMORY_MASK-1500) ) { navι_dm_post_error(View rmt_TooBιg) ,- return false,- •endif } else ( sel = Selectιon2Ascιι(vifcw,tvιew->sel,false, false) ; ) if ( sel * =NULL ) return false; lf ( xvt_cb_open(true) ) { selcopy = xvt_cb_alloc_data( (long) strlen(εel)+1) ; for ( ptl = sel, pt2=selcopy; (*pt2++ = *ptl++) ; ), xvt_cb_put_data(CB_TEXT,NULL, (long) strlen(εel1+1, (PICTURE) 0); xvt_cb_free_data() ; if ( focus==NULL_WIN it ( sel = Selectιon2Html(view,tvιew->εel,true) ) '=NULL ) ( len = SelectionTransLen!) ; selcopy = xvt_cb_alloc_data(len) ; for ( ptl = sel, pt2=selcopy, ι=0; κlen; *pt2++ = *ptl++, ++ι ), xvt_cb_put_data(CB_APPL, "HTML" ,len, (PICTURE) 0) ; xvt_cb_free_data() ; ) xvt_cb_close() ; ViewSetMenu(view,false) ,- /• Update status of Paste */ return true, ) else xvt_scr_beep() ; return false; } void XVT_CALLCONVl ViewCopy(WINDOW w) ( _VιewCopy(w) ; ) void XVT_CALLC0NV1 ViewCopyURL(WINDOW w) ( View "view = (View *) xvt_vob3_get_data(w) ,- char 'start, 'end, 'tit; char buf er[500] , buf2[500], anchor( 0] ; /* If the selection contains a link use its URL */ if ( 'vιew->sel.start.none it SelectionConta sTag(view,A_TAG,NULL,istart,tend) ) ( if ( HTML_HasAttr(start,buffer,sizeof(buffer) , "HREF") 1 { URLTrans(bu fer,vιew->page->url,vιew->page->base,buf2,anchor, sizeof(buf2) ,sizeo (anchor) ) , if ( anchorlO] '='\0' ) ( strca (buf2, "•") ; strcat(buf2,anchor) ; } tit = NULL; if ( HTML_HasAttr(start,bu fer,sizeof(buffer) , "TITLE") ) tit = buffer; CopyUrlAdd(vιew,buf2,tιt, false) , ) else if ( HTML_HasAttr(start,buffer,sizeof(buffer) , "NAME" ) ) ( if ( vιew->page->noname ) { viewcmd. c Fri Mar 24 13 : 23 :48 1995 12 navι_dm_post_message (Docedιt_UnrealName/ * " Page does not have a real naune Please Save i " * / ) , return . ) strcpy(buf2,vιew->page->url) ; if ( buffer(O) > = ' \ ' ) ( strcat(buf2, "#") , strcat (buf2,buffer) ,- ) CopyUrlAdd(vιew,buf2,vιew->page->tιtle, false) , } else xvt_scr_beep{ ) ; else if ( SelectionContainsTag(view,IMG_TAG, ULL, istart,iend) ) { if ( HTML_HasAttr<start,buffer,sizeof(buffer) , "IMG") ) { URLTrans(buffer,vιew->page->url,vιew->page->base,buf2,anchor, sizeof (buf2) ,sizeof (anchor) ) , CopyUrlAdd(view,buf2, ULL, false) ; } else xvt_scr_beep( ) , else { if ( vιew->page->noname ) { navι_dm_post_message(Docedιt_UnrealName/*"Page does not have a real name Plea se Save it"*/ ) return, CopyUrlAdd(vιew,view->page->url,view->page->tιtle, false) , ) void XVT_CALLC0NV1 ViewClear(WINDOW w) { View "view = (View *) xvt_vob3_get_data(w) ; WINDOW focus, char buffer [400] ; if (( focus=xvt_scr_get_focus_vob3 () ) '-vιew->pane ) { mt type = xvt_vob3_get_type(focus) , if ( type==WC_EDIT | | type==WC_LISTEDIT ) ( int first, last; xvt_vobj_get_tιtie(focus,buffer, sizeof(buffer) ) , xvt_ctl_get_text_sel (focus, ifirst, tlast) ,- strcpy(buf er+first,buffer+last) , xvt_vob3_set_tιtle(focus,buffer) ; return, ) ) if ( !VιewReadOnly(vιew) ) ViewChange(view, * " , 0, false, false) ) void XVT_CALLC0NV1 ViewCut(WINDOW w) { View 'view = (View *) xvt_vob3_get_data(w) ; WINDOW focus; if ( VιewReadOnly(vιew) ) return, ) if ( _VιewCopy(w) ) ViewClear(w) , Fri Mar 24 13:23:48 1995 13 static void _UndoIt(Vιew 'view. Undo 'actor, int ιs_undo) ( VPara *vp; char 'temp, "field; Page 'page = vιew->page; Selection sel; int sel_wasnt_drawn = vιew->dontdrawsel,- if ( actor==NULL ) { xvt_scr_beep() ; return, ) else if ( actor->type==u_replace | | actor->type==u_typmg ) ( ViewShowSelection(view,actor->pnums,actor->offsets, actor->pnume,actor->offsete) ,- vιew->page->dontsqueezenoops = true, VιewChange(vιew,actor->str,HTML_len(actor->str) ,ιs_undo, false) , vιew->page->dontsqueezenoops = false; ) else if ( actor->type==u_lιtteral ) { /* Generated by Squeeze out NoOps to mark automagic text changes */ ViewShowSelection(view,actor->pnumε,actor->offεetε, actor->pnume,actor->offsete) ,- vιew->page->dontsqueezenoops = true; VιewChange(vιew,actor->str,HTML_len(actor->str) ,ιs_undo, falεe) , vιew->page->dontsgueezenoops = false; ) else if ( actor->type == u_tagtext ) { vp = ViewGetVPara(view, ULL,actor->pnums) ; temp = vp->para->tagtext; vp->para->tagtext = actor->str; actor->str = NULL, UndoAddTagText(page,ιs_undo,actor->pnums,temp) ,- if ( vp->para->tag==FORM_TAG ) DocFormCheck(page,vp->para) ,- } else if ( actor->type >= u_tιtle it actor->type <= u_style ) ( switch ( actor->type ) { case u_tιtle: field = tpage->tιtle; break; case u_up: field = tpage->upl, break; case u_documen • field = tpage->docname; break,- case u_style: field = tpage->style; break, default: IError("Invalid header undo"); return; ) temp = *field; 'field = actor->str, actor->str - NULL; UndoAddHeader(page,ιs_undo,actor->type, emp) ; if ( actor->type==u_tιtle 1 PageSetTitle(page, ULL) ; else if ( page->doc'=NULL ) DocPageHeaderChange (page->doc,page,actor->type1 , PageSetChanged(vιew->page,true) ,- } else if ( actor->type == u_togglestyle ) { ViewShowSelection(view,actor->pnums,actor->offsets, actor->pnume,actor->offsete) ; VιewToggleStyle(vιew,actor->str,ιs_undo) ; } else if ( actor->type «= u_multιple ) { Undo 'base = ιs_undo?page->redoes:page---undoes; Undo 'subs, 'psub; VιewUndrawSel(vιew,ivιew->sel) ; /* Clear selection */ vιew->dontdrawsel = true; for ( subs=actor->sub, subs'=NULL, subs=psub ) { psub = subs->prev; _UndoIt(view,subs,ιs_undo! ; ) UndoAddMultiple(page,ιs_undo,base) ,- actor->sub = NULL, /' We already freed them */ Fri Mar 24 13:23:48 1995 14 } else if I actor->type == u_removepara ) { ViewsRemoveParaTag(view->page,ViewGetVPara(view,NULL,actor->pnums) ->para,is_undo) ; } else if ( actor->type == u_alterpara ) { ViewUndrawSel(view,tview->sel) ,- /* Clear selection */ view->dontdrawsel = true; ViewsAlterParaTag(view->page,ViewGetVPara(view, ULL,actor->pnums)->para, actor->offsets,is_undo) ; ) else if ( actor->type == u_insertpara ) { sel.star .o fset = 0; sel.sta t,para = ViewGetVPara(view,NULL,actor->pnums) ,- sel.end.para = ViewGetVPara(view,sel.start.para,actor->pnume) ; sel.end.offset = sel.end.para->para->tlen; sel.start.none = false; ViewsInsertParaTag(view->page,isel,actor->offsetε,is_undo) ,- } else { xvt_scr_beep() ; ) if ( actor->disk tt is_undo ) { PageSetChanged(view->page,false) ; page->redoes->disk = true; } else PageSetChanged(view->page,true) ; actor->prev = NULL; UndoFree(actor) ; if ( ( !sel_wasnt_drawn it view->dontdrawsel) || ( !view->sel.start.none it !view->sel.s tart.drawn) ) { view->dontdrawsel = false; ViewDrawSel(view,tview->sel) ; ) ViewSelectionHasChanged(view) ,- } static void Undolt(View "view, int is_undo) { Undo "actor, *hold_redoes=NULL; Page 'page = view->page; View *vs; if ( ViewReadOnly(view) ) ( return; } else if ( is_undo ) { actor = page->undoeε; if ( actor!=NULL ) page->undoes = actor->prev; } else { actor = page->redoes; if ( actor!=NULL ) page->redoes = actor->prev; hold_redoes = page->redoes; page->redoes = NULL; } _UndoIt(view,actor,is_undo) ; if ( hold_redoes!-NULL ) { if ( page->redoes!=NUI_L ) IErrorI"Redoes are screwed up"); page->redoes * hold_redoes; ) for ( vs=page->views; vs!=NULL; vs=vs->nextsame ) if ( vs=={View •) xvt_vobj_get_data(vs->w) 1 xvt_menu_set_item_enabled(vs->w,PageMenu_Redo,page->redoes!=NULL) ; ) void XVT_CALLC0NV1 ViewUndo(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) ; Undolt(view,true) ; ) ▼iewc-ad.c Fri Mar 24 13 :23 :48 1995 15 void XVT_CALLCONVl ViewRedo (WINDOW w) { View 'view = (View * ) xvt_vob3_get_data (w) ,- Undolt (view, false ) ; ) void XVT_CALLCONVl ViewFind (WINDOW w) { View 'view = (View * ) xvt_vobj_get_data (w) ; i f ( vιew->wιnfo->fιnd_rpl ' =NULL_WIN ) navι_vob3_raιse (vιew->wιnfo->fmd_rpl ) ,- else i f ( ' (vιew->wιnfo->f ιnd_rpl = navι_xvt_dlg_create_res (WD_MODELESS , FNR, EM_ALL, FNR_eh, ( long) view) ) ) xvt_dm_post_error ( "Can ' t open dialog" ) ; ) void XVT_CALLCONVl ViewFindAgam (WINDOW w) { View 'view = (View * ) xvt_vob3_get_data (w) ,- FιndAgam(vιew) , ) static int XVT_CALLC0NV1 Open0k(voιd 'ctx.char *url,struct chooserinfo *ιnfo) ( View 'view = (View *) ctx; OpenURL(url, view,true,info->_as_type, false, "NaviPress Open Dialogue"), return 1; } void XVT_CALLC0NV1 AnyOpen(WINDOW w) { char buf er[400]; buffer[0)='\0' , if ( w'=NULL_WIN ) { view = (View *) xvt_vob3_get_data(w) ,- if ( vιew->tag == TAG_VIEW ) strcpy(buffer,vιew->page->url) , else strcpy(buffer,( (DocView *) vιew)->doc->name) , ) Chooselt(view,Vιewcmd_Open/*"Open page or miniweb "*/.buffer,sizeof(buffer) CHOOSER_OPEN, OpenOk) , ) static mt DeleteO (void *ctx, char *url, struct chooserinfo 'unused) { Page *page=NULL; Document *doc=NULL; int dirty; DocPart 'dp, int asked=0, if ( (page-PageLooku Iurl, "",NULL) ) '=NULL ) { if ( page-.-changed ) if ( xvt_dm_post_ask("Delete", "Cancel" ,NULL, "This item has been modified, delete it anyway'")==RESP_2 ) return false,- asked = page->changed, ) else if ( (doc=DocLookup(url) ) '=NULL ) { /* Doc's can't be nested so it is safe to delete it as is */, dirty = doc->dιrty; for ( dp=doc->fιrst; 'dirty it dρ'=NULL; dp = dp->another ) f ( dp->loaded tt dp->loaded->changed 1 dirty = true; if ( dirty 1 if I xvt_dm_post_ask("Delete", "Cancel".NULL, "This item has been modified, delete it anyway'" 1==RESP_2 1 viewcmd.c Fri Mar 24 13:23:48 1995 16 return false; asked = dirty; J if ( !asked ) if! xvt__dm_post_ask("Delete" , "Cancel", NULL, "Are you sure you want to delete permanently?")==RESP_2 ) return false; DeleteURL(url) ; return 1; ) void XVT_CALLCONVl AnyDelete(WINDOW w) ( char buffer(400] ; buffer[0]='\0' ,- if ( w'=NULL_WIN ) { view = (View *) xvt_vob3_get_data(w) , if ( 'view ) strcpy(buffer, "") ,- else if ( vιew->tag == TAG_VIEW ) strcpy(buffer,view->page->url) ; else if ( ((DocView *) view)->selected 1 fsys_buιld_nameI ( (DocView *) view)->doc->naune, ((DocView *) view)->selected->relurl, buffer, sizeof(buffer) ) ; else strcpy(buf er, ( (DocView *) view)->doc->name) , ) Choosel (view,Vιewcmd_Delete/*"Delete page or miniweb . "*/,buffer,sizeof(buf er) , CHOOSER_DELETE, DeleteOk) ; } void XVT_CALLC0NV1 AnySearch(WINDOW w) ( View "view = NULL; char space(500J; lf ( w'=NULL_WIN ) view = (V ew *) xvt_vobj_get_data(w) ,- if ( GetDes (Vιewcmd_SearchServ/*"Pick a service to search.. "*/, space, sizeof(space) ) ) { if ( space(strlen(space)-1] '='/ ' ) strcat(space, "/"),- strcat(space,NS_OP_UrlPrefix) ; strcat(space, "/") ; strcat(space,NS_OP_GetSearchFormPιcker) ; SubmitURL(space, view, "NaviPress: Search"), void XVT_CALLC0NV1 AnyDescribe(char "full, mt ιs_doc) { char space[500] ; if ( !fsys_ιs_url(full) ) { xvt_dm_post_error("This is not applicable to local files"), return,- ) if ( GetDest(ιs_doc'Vιewcmd_DescrιbeWeb-Vιewcmd_Describe, space, sizeof(space) ) ) ( Form "form; .c Fri Mar 24 13:23:48 1995 17 if ( space[strlen(space)-1] '=' /' ) strcat{space, "/" ) , strcat(space,NS_OP_UrlPrefix) , strcat(space, "/* ) , strcat(space, S_OP_GetMetaTables) ; form = NewForm(NS_OP_UrlPrefιx, space, 0), AppendFormField(form, "Url", full, 0, 0), SubmitFormlfor , NULL, "NaviPress Describe"), void XVT_CALLC0NV1 AnyAdmin(WINDOW w) { char space[500] , if ( GetDest(Vιewcmd_Admin/""Pick a server to administer "*/, εpace, εizeof (εpace) 1 ) { if ( space[strlen(space)-1] '='/' ) strca (space, ' /") , strcat(space,NS_OP_UrlPrefιx) , strcat(space, "/") , strcat(space, S_OP_Admιn) , SubmitURL(space, NULL, "NaviPresε Admin"), ) ) static void XVT_CALLC0NV1 _VιewPermιssιons(WINDOW w, mt ιε_perm, int ιs_read) { View "view = (View *) xvt_vobj_get_data(w) , char space[500], *pt, char 'method, "urllab, char "url, if ( vιew->tag == TAG_VIEW ) url = vιew->page->url, else url = ((DocView *) view)->doc->name, if ( (pt = strstrlurl," //"))==NULL ) { if ( ιε_perm ) navι_dm_post_error(Vιewcmd_UseLocal/*"Use local filesystem to set permisεions '/) . else xvt_dm_post_error("This is not applicable to local files"), } else { Form "form, /* Put the server componant into space, then the save the local name */ /* for later use */ if ( (pt=strchr(pt+3, '/'))== NULL ) { strcpy(space,ur1) , pt = "/", ) else ( "pt = '\0' , strcpy(space,url) , *pt = '/' , ) strcat(space,"/"), strcat(space, S_OP_UrlPreflx) , strcat(space, */") , strca (space,NS_OP_GetUpdateOrEntryForm) strca (space,"/"), strca (space,ιs_perm'NS_OP_Permιεειons:NS_0P_Cost) , .c Fri Mar 24 13:23:48 1995 18 form = NewForm(NS_OP_UrlPreflx, space, 0) , if I ιs_perm ) { method = "Hιde.permιssιon_method", urllab = "Hιde.permιεειon_url" , } else { method = "Hιde.coεt_method" , urllab = "Hιde.cost_url", } AppendFormFiel (form, method, ιε_read==-l'"POST" :ιε_read'"GET" "PUT", 0, 0) AppendFormFieldIform, urllab, pt, 0, 0), SubmitFormlform, NULL, "NaviPress. Cost/Permissions"); ) void XVT_CALLC0NV1 ViewPermissions(WINDOW w,mt ιs_read) { _VιewPermιssιons(w,true,ιs_read) , ) void XVT_CALLCONVl ViewCosts(WINDOW w,int ιs_read) { _VιewPermιssιonε(w, false,ιs_read) , ) void XVT_CALLC0NV1 ViewAutoLmk(WINDOW w) { View "view = (View *) xvt_vob3_get_data(w) , char space[500] , if ( VιewReadOnly(vιew) ) return, if ( GetDest(Vιewcmd_LιnkServ/*"Pick a service to search for links "*/, space, sizeo f(space)) ) { vιew->page->frozen = true, ViewSetCursor(view) , if ( space[strlen(space)-1] '='/' ) strcat(space, "/") , strcat(space,NS_OP_UrlPreflx) , strcat(space, "/"),- strcat(space, S_OP_Navιlmk) ; PageSave(view->page,space, false,false, view, true), ViewSetMessage(view,xvt_res_get_str(Vιewcmd_Waitmg,space,sizeof(εpace) ) /'"Waiting for suggestions "*/), AnyToggleStop(view,true) , t XVT_CALLC0NV1 ViewCharCmds(View 'view, EVENT 'event) { extern t pc_mappιng, _ι_appιng_done; switchlevent->v.chr.ch) { case K_COPY- if ( even ->v.chr.control ) VιewCopyURL(vιew->w) , else VιewCopy(vιew->w) ; break, case K_INS- if ( even ->v.chr.control ) VιewCopy(vιew->w) ; else if ( even ->v.chr.sh ft ) VιewPaste(vιew->w) , else return false, Fri Mar 24 13:23:48 1995 19 break case K_CUT: ViewCut(vιew->w) ,- break case K_PASTE: ViewPaste(vιew->w) ; break case K_xUNDO: ViewUndo(vιew->w) ; break case K_xREDO: ViewRedo(vιew->w) ; break case K_xFIND: VιewFιnd(vιew->w) ,- break case K_xOPEN: AnyOpen(vιew->w) , break case K_xSTOP: AnyStopCo___m(view->w) ; break case 'B'- ' 9 ' : VιewBack(vιew->w) ,- break case 'F'-' ~ ' ■ VιewForeward(vιew-_>w) ,- break case 'H'-'θ' : ViewBackspace(vιew->w) ; break case '\177' : if ( mappιng_done ) ViewDelchar(vιew->w) ; else if ( !pc_mappιng ) ViewBackspace(vιew->w) ; else ViewDelchar(view->w) ,- break case 'D'-'β': /* Λ D gets mapped to ' - n hooksx.c * ViewDelchar(view->w) ; break case 'W'- 'β' : VιewBackword(vιew->w) ; break case • ' } • - • - , • -. VιewBacklιne(vιew->w) ,- break case '\n' : VιewExιtReturn(vιew->w) ; break case '\r' . VιewReturn(vιew->w) ; break case '\t' : VιewTab(vιew->w) ; break default: return(false) ; ) return(true) ; ) void XVT_CALLC0NV1 ViewPageSetup(WINDOW w) { View "view = (View *) xvt_vobj_get_data(w) ; mt size; if ( vιew->page->prcd==NULL ) vιew->page->prcd = xvt_prιnt_create(tsize) , xvt_dm_post_page_setup(vιew->page->prcd) ; } /* Create a fake view attached to the printer. We can't do this inside the */ /* print thread itself because we may need to scroll the original view to n */ /* order to take pictures of the controls */ static View * XVT_CALLC0NV1 ViewCreatePrintViewfView "realview) { Page "page = realview->page; View 'printview = newVιew(NULL) ; int oldleft = realvιew->text_offief , oldtop = realvιew->text_offtop; long phres, pvres, pw, ph; -iawcmd.c Fri Mar 24 13:23:48 1995 20 • if 1 xvt_app_escape(XVT_ESC_GET_PRINTER_ INFO, page- >prcd, tph, tpw, tpvreε, iphres) ; prιntvιew->wwιdth = pw,- /" We get a half inch leεs in the print band than PRINTER_HEIGHT reports */ pπntvιew->wheιght = ph-pvres/2; •else phres = xvt_vobj_get_attr (NULL_WIN,ATTR_PRINTER_HRES) ,- pvres = xvt_vob3_get_attr(NULL_WIN,ATTR_PRINTER_VRES) ; pπntvιew->wwιdth = (short) xvt_vob3_get_attr (NULL_WIN,ATTR_PRINTER_ WIDTH) , prmtvιew->wheιght = (short) xvt_vooj_get_attr (NULL_WIN,ATTR_PRINTER_HEIGHT) pvres/ 2; /' We get a half inch less in the print band than PRINTER_HEIGHT reports */ •endif if ( (prιntvιew->hfact = (phres+prιntvιew->hres/2 ) /prιntvιew->hres )< 1) prιntvιew->hfact = 1; lf ( ( prιntvιew->vfact = (pvres+prιntvιew->vres/2 ) /pπntvιew->vres )< 1) pπntvιew->v act = 1, prmtvιew->hres = phres; prιntvιew->vreε = pvres, pπntvιew->oldfreeze = page->frozen; prιntvιew->w = xvt_pπnt_create_wιn(page->prcd, page->tιtle' =NULL?page->tltle: page- >faketι tie' =NULL?page-> itle: page->url) , if ( prιntvιew->w==NULL_WIN ) { myfree (pπntview) ; return (NULL) ; } page-> rozen = true, pr int view- >page = page; prιntvιew->nextsame = realview; /* We can't call ViewSetup on this guy, instead we do this */ prιntvιew->pane = pnntvιew->w, prιntvιew->sheet = real ιew->sheet; xvt_dwιn_set_font (pπntvιew->w,prmtvιew->sheet->paras [P_Normal] .fid) , xvt_dwιn_get_font_metncs (prιntvιew->w,tld, tas, ids) ; pπntvιew->text_overhead = 2* (ld+as+ds) ; ViewMetrics(printview) , ViewSetHScroll(realview,oldleft) ; ViewSetVScroll(realview,oldtop) ; return(prmtview) ,- ) /* This is the routine inside the print thread that prints stuff */ /* we are passed in a fake view that is attached to the printer, and */ /* we pretend bits of it (bands) get exposed, and then draw those bits */ •ifdef STDC_ Static BOOLEAN XVT_CALLCONVl ViewDoPrmt(long lp) { •else Static BOOLEAN XVT_CALLC0NV1 ViewDoPrmt(lp) long lp, { •endif View 'printview = (View *) VιewCreatePrιntVιew( (View *)lp). Page 'page; RCT 'ret; nt len, output; if( !printview) return false; page = printview->page; output = 0; while I output<pnntvιew->text_heιght ) { Fri Mar 24 13:23:48 1995 21 if ( !xvt_prιnt_open_page(page->prcd) ) break; len = 0; while ((ret = xvt_print_get_next_band() ) '=NULL ) len += ViewPπntBand(printview,output,len,ret) ,- if ( !xvt_prιnt_close_page(page->prcd) ) break,- output += len; ) page->frozen = printview->oldfreeze; xvt_vob3_destroy(prιntvιew->w) ,- ViewFree{printview,true) ,- return(true) ; ) void XVT_CALLC0NV1 ViewPrint(WINDOW w) { View "view = (View *) xvt_vobj_get_data(w) ; mt size; char buffer[100] ; if ( vιew->page->prcd==NULL ) vιew->page->prcd = xvt_prιnt_create(tsize) ,- if ( 'xvt_prmt_ιs_valιd(vιew->page->prcd) ) { navι_dm_post_warnιng(Vιewcmd_Setup/*"Not set up for current printer"*/),- VιewPageSetup(w) ; if ( !xvt_prιnt__ιs_valιd(vιew->page->prcd) ) { ViewSetMessage(view.xvt_reε_get_εtr(Vιewcmd_Aborted,buffer,sizeof(buffer) ) /*"A borted"*/) ,- return; } } xvt_prιnt_start_thread(ViewDoPrmt, (long) view), ViewSetMessage(view, "Printing done" ) ,- ) void XVT_CALLC0NV1 ViewToggleShowFormBorder(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) ,- vιew->showform = !view->showform; vιew->showformchanged = true; VιewRedraw(vιew) ; ViewSetMenu(view,false) ; ) void XVT_CALLC0NV1 ViewNormalFormat(WINDOW w) ( View "view = (View *) xvt_vobj_get_data(w) ,- Position "spoε, "epos; VPara "vpara; if ( view->sel.start.none 1 ( vpara = view->caret.para; spos = epoε = ivιew->caret; } else { vpara = vιew->sel.start.para; spos = tvιew->sel.start; epos = tvιew->sel.end; ) if ( 'vιew->sel.start.none it vpara'=NULL it vpara->parent'=NULL it vpara->parent == epos->para->parent it vpara == vpara->parent->subs tt epos->para->post==NULL tt AtStartOfPara(spos) it AtEndOfPara(epos) ) { if ( vιew->sel.start.para->parent->ρara->tag>=Hl_TAG tt vιew->sel.star .para->ρarent->para->tag<=H7_TAG ) Fri Mar 24 13:23:48 1995 22 ViewHead g(w,0) , /* Should never happen, see next major block */ else if ( vιew->sel.start.para->parent->para->tag>=DD_TAG tt vιew->sel.start.para->parent->para->tag<=LI_TAG ) ViewSetLis (w,0) , else f ( vιew->sel.start.para->parent->para->tag==FORM_TAG ) VιewUnForm(w) ; else ViewSetPara(w.P_TAG) ; else if ( 'vιew->sel.start.none it vpara'=NULL it vpara->parent'=NULL tt vpara->parent->paren '=NULL tt epos->para->paren '=NULL it vpara->parent->parent == epos->para->parent->parent &f- vpara == vpara->parent->parent->subs->subs tt epos->para->post==NULL it AtStartOfPara(spos) it AtEndOfPara(epos) it vpara->paren ->para->tag>=DD_TAG tt vpara->parent->para->tag<=LI_TAG ) { ViewSetList(w,0) , else VιewExιtReturn(w) . /* Remove the link, leave the anchor */ void XVT_CALLCONVl ViewUnlink(WINDOW w) { View "view = (View *) xvt_vobj_get_data(w) , char buffer[400]; char *pt, 'start, 'end; Selection sel; if I VιewReadOnly(vιew) ) return, if ( !SelectionContainsTag(view, A_TAG, NULL, istart, tend)) return; sel = vιew->sel; sel.end.para = sel.start.para, sel.start.offset = start-sel.start.para->para->text; sel.end.offset = end-sel.star ,para->para->tex , • sel.start.mapped = false; sel.start.pmapped = true, sel.end.mapped = false, sel.end.pmapped = true; ViewUpdateSel(view,tsel) , pt = vιew->sel.star .para->para->text + vιew->sel.star .offse , memcpy(buffer.pt,Taglncr(pt) ) ; buffer[Taglncr(pt) ]='\0' ,- ViewToggleStyle(view,buffer,false) ; ) void XVT_CALLCONVl ViewSetStyleMap(WINDOW w) { View 'view = (View *) xvt_vobj_get_data(w) , if ( VιewReadOnly(vιew) ) return; if (!navι_xvt_dlg_create_res(WD_MODAL, StlDlg, EM_ALL, StlDlg_eh, xvt_dm_post_error("Can't open dialog"), ) HFDoc.c Mad Mar 22 16:30:28 1995 1 /* This file was generated by XVT-Design 3.0, a product of: XVT Software Inc. 4900 Pearl East Circle Boulder, CO USA 80301 303-443-4223, fax 303-443-0969 Generated on Wed Mar 22 16:11:37 1995 •include "xvt.h" •include "xvtcm.h" •include "NaviPres.h* /* Custom control header files */ •include "toglbutn.h" •include "toolbar.h" /* Information about the window */ •define WIN_RES_ID DocWin •define WIN_FLAGS 0x83L •define WIN_CLASS "" •define WIN_BORDER W_DOC static char *xdPropList_0[] = { "MiniWeb_toolbar", /* title */ /* ACE Instance Data */ "AUTOSIZE", "HEIGHT=44", " PICBUTN=1 , 700 , \ "New MiniWebV " , " PICBUTN=2 , 710 , \ "New PageV , " PICBUTN=3 , 720 , \ "Open\ " " , "SEPARATORS", "PICBUTN=4,730, \"Import\"", "PICBUTN=5,740, \"Save As\"", ■ SEPARATOR=", "PICBUTN=22, 540, \"Stop Communications\"" , NULL /* NULL-terminate the array */ ); static int xdPropCount_0 = 11; •include "func.h" •include "doc.h" /' Handler for window DocWin ("MiniWeb") */ long XVT_CALLC0NV1 •if XVT_CC_PROTO DocWin_eh XVT_CALLCONV2 (WINDOW xdWindow, EVENT 'xdEvent) •else DocWin_eh XVT_CALLC0NV2 (xdWindow, xdEvent) WINDOW xdWindow; EVENT 'xdEvent; •endif ( short xdControlId = xdEvent->v.ctl.id; xvtcm_parent_event(xdWindow, xdEvent) ; switch ( dEvent->type) ( case E_CREATE: NVDoc . c Mad Mar 22 16 :30 :28 1995 toolbar_create(MiniWeb_toolbar, 0, 0, 521, 37, xdPropCount_0, xdPropList_0, xdWindow, WIN_RES_ID, WIN_FLAGS, WIN_ CLASS) /* Window haε been created; first event sent to newly-created window. */ { DocViewFillup(xdWindow) ; } break; case E_DESTRO : /* Window has been closed; last event sent to window. '/ xdRemoveHelpAssoc( xdWindow ); ( DocViewDelete(xdWindow) ; ) return 0L; caεe E_FOCUS: { /* Window has loεt or gained focus. */ DocPaneFocus(xdWindow,xdEvent->v.active) ; ) brea ; case E_SIZE: /* Size of window has been set or changed; sent when window is created or subsequently resized by user or via xvt_vobj_move. */ { DocViewSize(xdWindow) ; ) break; case E_UPDATE: /* Window requires updating. */ { DocHeadDraw(xdWindow,txdEvent->v.update.ret) ; ) break; case E_CLOSE: /* Request to close window; user operated "close" menu item on window system menu, or operated "close* control on window frame. Not sent if Close on File menu is issued. Window not closed unless xvt_vobj_destroy is called. */ { DocViewClose(xdWindow) ; ) break; case E_CHAR: /* Character typed. */ { DocChar(xdWindow,xdEvent) ; } break; HVOoc.e Mad Mar 22 16:30:28 1995 3 case E_MOUSE_UP: /* Mouse was released */ ( ) break; case E_MOUSE_DOWN: /* Mouse was pressed */ ( ) brea ; case E_MOUSE_DBL: /* » Mouse was double clicked */ { ) break; case E_MOUSE_MOVE: /* Mouse was moved */ { ) break,- case E_HSCROLL: { ) break; case E_VSCR0LL: { ) break; case E_C0MMAND: /* User issued command on window menu bar (menu bar at top of screen for Mac/CH) . */ { DocPaneFocus(xdWindow,true) ; do_DocumentMenu(xdWindow, xdEvent) ; ) break; case E_CONTROL: /* User operated control in window. */ { switch(xdControlId) { case Doc_First: { DocWinFirst(xdWindow) ,- ) break; default: break; ) } break; case E_F0NT: /* HFDOC.C Mad Mar 22 16:30:28 1995 User issued font command on window menu bar (menu bar at top of screen for Mac/CH) . */ { ) break; case E_TIMER: Timer associated with window went off. break; case E_USER: Application initiated. */ { XVTCM_C0NTR0L_INF0 'xdlnfo = XVTCM_GET_INFO(xdEvent1 ; switch (xdEvent->v.user.id) { case MinιWeb_toolbar: AnyUpdateToolbarButton(xdWindow, ( (T00LBAR_INF0 * Jxdlnfo) ->ctl_ιd) ; switch! ( (TOOLBAR_INFO * )xdlnfo)->ctl_ιd) { case 1 : BuildNewDoc ( ) ; break,- case 2 : BuιldNewPage( I (DocView *)xvt_vob3_get_data(xdWindow) ) ->doc) ; break,- case 3 : AnyOpen(NULL_WIN) ; break; case 4 : Doclmport (xdWindow) ; break; case 5 : DocSaveAs (xdWindow) ; break,- case 22 : AnyStopCom (xdWindow) ,- break; default: break,- ) default: break; ) ) break; default: break,- } xvt_tx_process_eventIxdWindow, xdEvent) ; return OL; Wad Mar 22 16:11:37 1995 This file was generated by XVT-Design 3.0, a product of XVT Software Inc. 4900 Pearl East Circle Boulder, CO USA 80301 303-443-4223, fax 303-443-0969 Generated on Wed Mar 22 16:11:37 1995 •include "xvt.h" •include "xvtcm.h" •include "NaviPres.h" •include "func.h" •include "doc.h" /* This function is the menu event handler for menu DocumentMenu */ void •if XVT_CC_PROTO do_DocumentMenu (WINDOW xdWindow, EVENT *xdEvent) •else do_DocumentMenu (xdWindow, xdEvent) WINDOW xdWindow; EVENT 'xdEvent; •endif { MENU_TAG tag = xdEvent->v.cmd.tag; switch (tag) { case All_NewDoc- /* Menu "New MiniWeb" */ { BuildNewDoc() , ) break, case DocumentMenu_32_8: /* Menu "New Page" */ { BuildNewPage( ( (DocView *)xvt_vob3_get_data(xdWindow) )->doc) ) break,- case All_Open: /* Menu "Open..." */ { AnyOpen(NULL_WIN) ; ) brea ; case DocumentMenu_32_38: /* Menu "Close" */ { DocViewClose(xdWindow) ; ) break, case All_Save: /* Menu "Save" */ { DocSave(xdWindow) ; ) break; case DocumentMenu_32__42. /* Menu "Save As.. ' */ { DocSaveAs(xdWindow) ; ) break,- case DocumentMenu_32_146- /* Menu "Import. ." */ HFDocMa.c Wad Mar 22 16: 11:37 1995 2 { Doclmport(xdWindow) ; ) break; case DocumentMenu_32_47: /* Menu "Exit" */ { ExitAppO ; } break; case All_Cut: /* Menu "Cut" */ { DocCut(xdWindow) ; } break; case All_Copy: /* Menu "Copy" */ { DocCopy(xdWindow) ; } break; case All_Paste: /* Menu "Paste" */ { DocPaste(xdWindow) ; ) break; case DocumentMenu_Clear: /* Menu "Clear" */ { DocClear(xdWindow) ,- ) break; case All_CopyURL: /* Menu "Copy URL" */ { DocCopyURL(xdWindow) ; ) break; case All_PasteURL: /* Menu "Paste URL" */ { DocPaste(xdWindow) ; ) break; case DocumentMenu_Stationery: /* Menu "Set Stationery" */ { DocWinTemplate(xdWindow) ,- ) break,- case DocumentMenu_Web: /* Menu "Clean Up" */ { DocChangeGraph(xdWindow,-1) ,- ) break; case DocumentMenu_Enlarge: /* Menu "Zoom In" */ { DocEnlarge(xdWindow) . ) break; case DocumentMenu_Reduce: /* Menu "Zoom Out" */ { DocReduce(xdWindow) ; ) break; case ProjectMenu_46_118: /* Menu "Describe MiniWeb..." */ { AnyDescribet ( (DocView *)xvt_vobj_get_data(xdWindow) )->doc->name,true) ) break; c Wad Mar 22 16:11:37 1995 3 case ProjectMenu_46_80: /* Menu "Search Server..." */ { AnySearch(NULL_WIN) ; ) break; case ProjectMenu_46_152_153: /* Menu "General..." */ { AnyAdmin(xdWindow) ; ) break; case ProjectMenu_46_152_228: /* Menu "GET Cost..." */ { ViewCosts(xdWindow,TRUE) ; } break,- case ProjectMenu_46_152_250 /* Menu "PUT Cost..." */ { ViewCosts(xdWindow,FALSE) ; ) break; case Pro3βctMenu_46_152_252 /* Menu "POST Cost. " */ { ViewCosts(xdWindow, -1) ; ) break,- case Pro3βctMenu_46_152_258: /* Menu "GET Permisεions..." •/ { ViewPermissions(xdWindow,TRUE) ; } break; case Pro3βctMenu_46_152_259: /* Menu "PUT Permissions..." */ { ViewPermissions(xdWindow,FALSE) ; ) break; case Pro3βctMenu_46_152_260: /* Menu "POST Permissions..." */ { ViewPermissions(xdWindow, -1) , ) break; case ProjectMenu_46_122_191: /* Menu "General..." */ { f ( !navι_xvt_dlg_create_res(WD_MODAL, Prefs, EM_ALL, Prefs_eh, 0L) ) xvt_dm_post_errorI"Can't open dialog") ,- ) break; case ProjectMenu_46_122_189: /* Menu "Extensions/MIME..." */ { if (!navι_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_MIME) ) xvt_dm_post_error("Can't open dialog"); break; Pro3βctMenu_46_122_190: /* Menu "MIME/Viewer..." */ { if ( !navι_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_VIEWERS )) xvt_dm_post_erro ("Can't open dialog"); ) break,- Pro3βctMenu_46_122_195: /* Menu "Save As Filters . " */ { if ( ! navι_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_SAVEAS) xvt_dm_post_error("Can't open dialog"), Wad Mar 22 16:11:37 1995 4 ) break,- case ProjectMenu_46_122_196: /* Menu "Miniweb Icons..." */ { if ( !navi_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_ICON) 1 xvt_dm_post_error("Can't open dialog"); ) break; case ProjectMenu_46_122_197: /* Menu "Naviservers... " */ { if ( !navi_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_DESTINA TIONS) ) xvt_dm_post_error("Can't open dialog"),- } break; case ProjectMenu_46_143: /* Menu "Delete..." */ { AnyDelete(xdWindow) ; ) break; case DocumentMenu_154_130: /* Menu "Global History..." */ { {extern WINDOW history; if ( history!=NULL_WIN ) navi_vobj_raise(history) ,- else if ( !navi_xvt_dlg_create_res(WD_MODELESS, History, EM_ALL, History_eh 0D) xvt_dm_post_errorI"Can't open dialog"); } ) break,- case DocumentMenu_154_159: /* Menu "Hot List..." */ ( {extern WINDOW hotlist; if I hotlist!=NULL_WIN ) navi_vobj_raise(hotlist) ; else if ( !navi_xvt_win_create_res(HotList, TASK_WIN, EM_ALL, HotLiεt_eh, 0L) ) xvt_dm_post_error("Can't open window") ,- ) ) break,- case DocumentMenu_35_54: /* Menu "Contents..." */ { LoadHelpWindowlNULL, "contents.htm") ,- ) break; case DocumentMenu_35_55: /* Menu "Find..." */ { LoadHelpWindo lNULL, "helpsrch.htm") ,- } break,- case DocumentMenu_35_57: /* Menu "Tutorial..." */ { LoadHelpWindo lNULL, "tutorial.htm") ; ) break ; case DocumentMenu_35_58 : / * Menu " Examples . . . " * / { LoadHelpWindowlNULL, "examples.htm") ; ) break; case DocumentMenu_35_60: /* Menu "FAQ..." */ { HFOocMn.c Wad Mar 22 16:11:37 1995 LoadHelpWindowlNULL, "faq.htm" ) ; } break,- case DocumentMenu_35_61 : /* Menu "About HTML. CreatePageWinFor("htt ://www.nesa.uiuc.edu/General/Internet/WWW/HTMLPrimer .html" break; case DocumentMenu_35_62: /* Menu "About URLs..." */ { CreatePageWinForI"http://www.nesa.uiuc.edu/demoweb/url-primer.html" ) ; ) break,- case DocumentMenu_35_64: /• Menu "Tech Support.. { LoadHelpWindowlNULL, "techsprt.htm" ) , ) break; case DocumentMenu_35_66: /' Menu "About NaviPress. if I !xvt_win_create_res(AboutW, TASK_WIN, EM_ALL, AboutW_eh, 0L) ) xvt_dm_post_error("Can't open window"); } break,- default: ( xvt_win_dispatch_event(TASK_WIN, xdEvent) ; ) break; HVFaøa.c Wad Mar 22 16:30:28 1995 1 /* This file was generated by XVT-Design 3.0, a product of: XVT Software Inc. 4900 Pearl East Circle Boulder, CO USA 80301 303-443-4223, fax 303-443-0969 Generated on Wed Mar 22 16:11:37 1995 •include "xvt.h" •include "xvtcm.h" •include "NaviPres.h" /* Custom control header files * •include "toglbutn.h" •include "toolbar.h" /* Information about the window */ •define WIN_RES_ID PageWin •define WIN_FLAGS 0x83L •define WIN_CLASS "" •define WIN_BORDER W_DOC static char *xdPropList_0[] = { "ToolBar", / « title */ /* Property List */ "DEBUG=FALSE" , "FILL_COLOR=LTGRAY" , "HORIZONTAL=TRUE" , "LEFT_OFFSET=0", "LEFT_START=6", "PLAIN=FALSE", "TASK_WIN=FALSE" , "TEXT_COLOR=BLACK", ■ TOP_OFFSET=3", "VERTICAL=FALSE", /* ACE Instance Data */ "AUTOSIZE", "HEIGHT»44", "PICBUTN=l,410,\"Cut\"", "PICBUTN=2,420. \"Copy\"" , "PICBUTN=3,430, \"Paste\"", "SEPARATORS", "PICBUTN=40,432, \"Describe URLV", "PICBUTN=41,434, VSearch ServerV", "PICBUTN=42, 36,\"Smart Link\"", "SEPARATOR=", NULL /* NULL-ter inate the array */ ); static int xdPropCount_0 = 24; static char *xdPropList_l[] = { -•1200", /* title */ NULL /* NULL-terminate the array • / ); static int xdPropCount_l = 1; •include "func.h" MPPaga. c Wad Mar 22 16: 30: 28 1995 •include "view. h" Handler for window PageWin ("Page"] long XVT_CALLCONVl •if XVT_CC_PROTO PageWιn_eh XVT_CALLCONV2 (WINDOW xdWindow, EVENT 'xdEvent) •else PageWιn_eh XVT_CALLCONV2 (xdWindow, xdEvent) WINDOW xdWindow; EVENT 'xdEvent; •endif ( short xdControlId = xdEvent->v.ctl.id, xvtcm_parent_event(xdWindow, xdEvent) , switch (xdEvent->type) ( case E_CREATE. toolbar_create(ToolBar, 0, 56, 566, 84, xdPropCount_0, xdPropList_0, xdWindow, WIN_RES_ID, WIN_FLAGS, WIN. CLASS) toglbutn_create(Page_ShowMιnιweb, 4, 88, 42, 123, xdPropCount_l, xdPropLιst_l, xdWindow, WIN_RES_ID, WIN_FLAGS, WIN_ CLASS) Window has been created, first event sent to newly-created window. { ViewWindowBorn(xdWindow) ; ) break; case E DESTROY: Window has been closed, last event sent to window '/ xdRemoveHelpAssoc( xdWindow ) { ViewWindowDies(xdWindow) ; ) return 0L; case E_FOCUS. Window has lost or gained focus. */ ViewPaneFocus(xdWindow,xdEvent->v.active) , ) break; case E_SIZE: /* Size of window has been set or changed, sent when window is created or subsequently resized by user or via xvt_vob3_.move */ { ViewResize(xdWindow,xdEvent) , ) break; case E_UPDATE: /* Window requires updating */ NPFage .c Wad Mar 22 16 :30:28 1995 3 { ViewHeadDraw(xdWindow,ixdEvent->v.update.rct) ; ) break; case E_CLOSE: /* Request to close window; user operated "close" menu item on window system menu, or operated "close" control on window frame. Not sent if Close on File menu is issued. Window not closed unless xvt_vob3_destroy is called. */ { ViewClose(xdWindow) ; } break; case E_CHAR: /* Character typed. */ { ViewTransfer(xdWindow,xdEvent) ; ) break,- case E_M0USE_UP: /* Mouse was released */ { ) break,- case E_MOUSE_DOWN: /* Mouse was pressed */ ( ViewTestFocus(xdWindow) ,- } break,- case E_MOUSE_DBL: /* Mouse was double clicked */ { ViewTestFocus(xdWindow) ,- ) break; case E_MOUSE_MOVE: /* Mouse was moved */ { ) break; case E_HSCROLL: { /* Horizontal scrollbar on frame was operated */ } break; case E_VSCROLL: { /* Vertical scrollbar on frame was operated MPPaga.c Wad Mar 22 16:30:28 1995 User issued command on window menu bar (menu bar at top of screen for Mac/CH) . ViewTestFocus(xdWindow) ; do_PageMenu(xdWindow, xdEvent) ,- break; case E_CONTROL: User operated control in window. switch(xdControlId) { case Page_Title: Edit control was operated. */ if (xdEvent->v.ctl.ci.v.edit.focus_change) { if (xdEvent->v.ctl.ci.v.edit.active) { focus has entered the control • / ViewFieldMenus(xdWindow) ; ) else { focus has left the control */ ViewSetTitle(xdWindow) ; PageCheckDocTitle(xdWindow) ; ) else { Contents of control were changed */ ViewSetTempChanged(xdWindow) ; break,- case Page_URL: { if (xdEvent->v.ctl.ci.v.edit.focuε_change) { if (xdEvent->v.ctl.ci.v.edit.active) { HPPaga .c Wad Mar 22 16 : 30 : 28 1995 5 •i f XVTWS == MACWS WINDOW w = xvt_win_get_ctl (xdWindow, Page_URL ) ; xvt_scr_set_f ocus_vobj (w) ,- •endi f ViewFieldMenuε (xdWindow) ; } else { / * focus has left the control */ /"Should not need this but under windows widget*/ /* modifies the title without telling us*/ ViewURLModified(xdWindow) ,- ) } else { ViewURLModified(xdWindow) ; ) ) break; default: break,- ) ) break; case E_FONT: /* User issued font command on window menu bar (menu bar at top of screen for Mac/CH) . */ { } break,- case E_TIMER: /* Timer associated with window went off. */ { ) break,- case E_USER: /* Application initiated. */ { XVTCM_CONTROL_INFO 'xdlnfo = XVTCM_GET_INFO(xdEven ) ; switch (xdEvent->v.user.id) { case ToolBar: AnyUpdateToolbarButton(xdWindow, ( (TOOLBAR_INFO *)xdlnfo)->ctl__id) , • switch! ( (TOOLBAR_INFO *Jxdlnfo) ->ctl_id) { case 1 : ViewCut (xdWindow) ; break; case : ViewCopytxdWindow) ; brea ; case 3 : ViewPaste(xdWindow) ; break,- case : ViewClear(xdWindow) ; break; case 5: ViewSetStyle (xdWindow, B_TAG) ; break,- case 6 : HPFaga.c Wad Mar 22 16:30:28 1995 VιewSetStyle(xdWmdow, I_TAG) ,- break; case 7: VιewSetStyle (xdWmdow, U_TAG) ; break ; case 8 : VιewSetStyle (xdWmdow, TT_TAG) , break ; case : ViewSetStyleIxdWindow, 0) ,- break; case 10: ViewCreateLinkWin(xdWindow) ,- ,- brea ; case 11 : ViewCreatelmageWin(xdWindow) ; break,- case 12 : VιewInsHR(xdWindow) ,- break, case 13 : ViewHeading (xdWindow, 1) ; break, case 14: ViewHeading (xdWindow, 2) ; break; case 15: ViewSetLis (xdWindow,UL_TAG) ; break; caεe 16: ViewSetLis (xdWindow,OL_TAG) , break; case 20: ViewBac IxdWindow) ; break, case 21. ViewForeward(xdWindow) , break, case 22 - AnyStopComm(xdWindow) ; break, case 30: HelpForWindow(xdWindow) ; break; case 40: AnyDescribe ( t (View * )xvt_vobj_get_data (xdWindow) ) ->page->url, false break,- case 41: AnySearch(xdWindow) ,- break; case 42 : ViewAutoLink(xdWindow) ; break; } break; case Page_ShowMιnιweb: toglbutn_set_state ( xvtcm_get_ctl_wιndow ( xdWindow, Page_ShowM web) , UP ) DocWithPage(( (View *) xvt_vobj_get_data (xdWindow) ) ->page) ; break; case -1: default.- break; MFPagra.c Wad Mar 22 16:30:28 1995 ) ) break; default: break; ) xvt_tx_process_event(xdWindow, xdEvent) ; return 0L; KFPageMn. c Thu Mar 23 14 : 55 : 29 1995 1 / * This file was generated by XVT-Design 3.0, a product of: XVT Software Inc. 4900 Pearl East Circle Boulder, CO USA 80301 303-443-4223, fax 303-443-0969 Generated on Thu Mar 23 14:55:29 1995 •include "xvt.h" ♦include "xvtcm.h" •include "NaviPres.h" •include "view.h" ♦include "ht l.h" *» ♦include "func.h" /* This function is the menu event handler for menu PageMenu */ void ♦if XVT_CC_PROTO do_PageMenu (WINDOW xdWindow, EVENT *xdEvent) •else do_PageMenu (xdWindow, xdEvent) WINDOW xdWindow; EVENT 'xdEvent; •endif ( MENU_TAG tag = xdEvent-_-v.cmd.tag; switch (tag) { case All_NewDoc: /* Menu "New MiniWeb" */ ( BuildNewDoc!) ; ) break; case PageMenu_78_69: /* Menu "New Page" */ { Page 'page = ((View *)xvt_vobj_get_data(xdWindow) )->page; if(page->doc) BuildNewPage(page->doc) ; else BuildNewDocWithPage! 1 ; ) break,- case All_Open: /* Menu "Open..." */ ( AnyOpenIxdWindow) ,- ) break; case PageMenu_Close: /* Menu "Close" */ { ViewClose(xdWindow) ,- ) break; case All_Save: /* Menu "Save" */ { ViewSave(xdWindow) ; ) break,- case PageMenu_78_85: /* Menu "Save As..." */ HPPagaMn.c Thu Mar 23 14:55:29 1995 2 { ViewSaveAs(xdWindow) ; ) break; case PageMenu_EmbedFile: /* Menu "Import..." */ { ViewInsFile(xdWindow) ; ) break; case PageMenu_78_88: /* Menu "Print Setup..." */ { ViewPageSetup(xdWindow) ; ) break; case PageMenu_78_89: /* Menu "Print..." */ { ViewPrin (xdWindow) ; } break; case PageMenu_78_91: /* Menu "Exit" */ { ExitApp() ; } break; case All_Undo: /* Menu "Undo" */ { ViewUndo(xdWindow) ,- ) break; case PageMenu_Redo: /* Menu "Redo" */ { ViewRedo(xdWindow) ,- } break; case All_Cut: /* Menu "Cut" */ { ViewCut(xdWindow) ,- ) break; case All_Copy: /* Menu "Copy" */ { ViewCopy(xdWindow) ; } break; case All_Paste: /* Menu "Paste" */ { ViewPaste(xdWindow) ; ) break; case PageMenu_Clear: /* Menu "Clear" */ { ViewClear(xdWindow) ; ) break; case PageMenu_All: /* Menu "Select All" */ { ViewSelectAll( (View *) xvt_vobj_get_data(xdWindow) } break; case All_CopyURL: /* Menu "Copy URL" */ { ViewCopyURL(xdWindow) ,- ) break; HPPagaMn.c Thu Mar 23 14:55:29 1995 3 case All_PasteURL: /* Menu "Paste URL" */ { ViewPaste(xdWindow) ; ) break; case PageMenu_Fιnd: /* Menu "Find / Replace..." */ { ViewFin (xdWindow) ; ) break; case PageMenu_FmdAgaιn. /* Menu "Find Next" */ { ViewFindAgain(xdWindow) ,- ) break; case PageMenu_Attr butes: /* Menu "Get Attribute.. " */ { ViewAttributeDispatch(xdWindow) ; ) break, case PageMenu_HRule: /* Menu "Horizontal Rule" */ ( ViewInsHR(xdWindow) ; ) break; case PageMenu_BR: /* Menu "Forced Line Break" */ { VιewInsBR(xdWindow) ,- ) break,- case PageMenu_Lιnk: /* Menu "Link..." */ { ViewCreateLinkWin(xdWindow) , ) break; case PageMenu_Bookmark: /* Menu "Anchor.. " */ { ViewInsAnchor(xdWindow) ,- ) break; case PageMenu_Image • /* Menu "Image. ." */ ( ViewCreatelmageWinIxdWindow) ; ) break; case PageMenu_PιctMap: /* Menu "Image Map..." */ ( ViewMapIxdWindow) ; ) break,- case PageMenu_Unlιnk: /* Menu "Unlink" */ { ViewUnlink(xdWindow) ; ) break; case PageMenu_Insert_148: /* Menu "Special Character" */ { if I !navι_xvt_dlg_create_res(WD_MODAL, Latinl, EM_ALL, Latιnl_eh, xvt_vobj_get_data(xdWindow) ) ) xvt_dm_post_erro I"Can' open dialog"), } break; case PageMenu_NormalFormat: /* Menu "Remove Format" */ { HFPagaMn.c Tbu Mar 23 14 : 55 :29 1995 4 ViewNormal Format (xdWindow) ; ) break; case PageMenu_Plaιn: /* Menu "Plain" */ { ViewSetStyleIxdWindow,0) ,- ) break; case PageMenu_Bold- /* Menu "Bold" */ { ViewSetStyleIxdWindow,B_TAG) ; ) break,- case PageMenu_Italιc: /* Menu "Italic" */ { ViewSetStyleIxdWindow,I_TAG) ,- } break; case PageMenu_Underlιne: /* Menu "Underline" */ { ViewSetStyle(xdWindow,U_TAG) ; ) break; case PageMenu_Fιxed: /* Menu "Fixed Pitch" */ { ViewSetStyle(xdWindow,TT_TAG) ; ) brea ; case PageMenu_Sub: /* Menu "Subscript" */ { ViewSetStyle(xdWindow,SUB_TAG) , ) break; case PageMenu_Format_Sup: /* Menu "Superscript" */ { ViewSetStyle(xdWindow,SUP_TAG) , ) break; case PageMenu_Cιtatιon: /" Menu "Citation" */ { ViewSetStyle(xdWindow,CITE_TAG) ; ) brea ; case PageMenu_Code: /* Menu "Code" */ { ViewSetStyle(xdWindo ,C0DE_TAG) ; } break; case PageMenu_Defmιtιon: /* Menu "Definition" */ { ViewSetStyle(xdWindow,DFN_TAG) ; } brea ; case PageMenu_E_mphasιs. /* Menu "Emphasis" */ { ViewSetStyle(xdWindow,EM_TAG) ; ) break; case PageMenu_Keyboard /* Menu "Keyboard" */ { ViewSetStyle(xdWindow,KBD_TAG) , ) break; case PageMenu_Sample. /* Menu "Sample" */ HPPagβMn.c Thu Mar 23 14:55:29 1995 5 { ViewSetStyleIxdWindow,SAMP_TAG) ,- ) break; case PageMenu_Strong: /* Menu "Strong" */ { ViewSetStyle(xdWindow,STRONG_TAG) ; ) break; case PageMenu_Varlable: /* Menu "Variable" */ { VιewSetStyle(xdWιndow,VAR_TAG) ; ) break; case PageMenu_Headmgl: /* Menu "Hdg 1" */ { ViewHeading(xdWindow,1) ; ) break; case PageMenu_H2: /* Menu "Hdg 2" */ { ViewHeading(xdWindow,2) , ) break; case PageMenu_H3: /* Menu "Hdg 3" */ { ViewHeading(xdWindow,3) ,- } brea ; case PageMenu_H4: /* Menu "Hdg 4" */ { ViewHeading(xdWindow,4) , } break,- case PageMenu_H5- /* Menu "Hdg 5" */ { ViewHeading(xdWindow,5) , ) break; case PageMenu_H6: /* Menu "Hdg 6" */ ( ViewHeading(xdWindow,6) , ) break,- case PageMenu_BQ: /* Menu "BlockQuote" */ { ViewSetPara (xdWindow, BLOCKQUOTE_TAG) , ) break; case PageMenu_PRE: /* Menu "Preformatted" */ { ViewSetPara(xdWindow,PRE_TAG) ; } break; case PageMenu_Address. /* Menu "Address" */ { ViewSetPara(xdWindow,ADDRESS_TAG) ; ) break; case PageMenu_UL: /* Menu "Unnumbered List" */ { ViewSetList(xdWindow,UL_TAG) ; ) break,- HPPagaMn.c Tbu Mar 23 14:55:29 1995 6 case PageMenu_OL : / * Menu "Numbered List " * / { ViewSetList(xdWindow,OL_TAG) ; ) break; case PageMenu_DL /* Menu "Definition List" */ { ViewSetList(xdWindow,DL_TAG) ; } break; case PageMenu_DT: /* Menu "Term" */ { VιewSetDefnTerm(xdWιndow) , } break,- case PageMenu_DD: /* Menu "Definition" */ { ViewSetLlstEntry(xdWindow) ; ) break; case PageMenu_For : /" Menu "Forms..." */ { View "view = (View *) xvt_vob3_get_data(xdWindow) ; if ( vιew->wιnfo->form'=NULL_WIN ) nav _vob3_raιse(vιew->wιnfo->form) ; else if ( 'navι_xvt_dlg_create_res(WD_MODELESS, FormDLG, EM_ALL, FormDLG_eh , (long) view) ) xvt_dm_post_error("Can' open dialog"); } break; caεe PageMenu_FormBorder: /* Menu "Show Border" */ { ViewToggleShowFormBorderIxdWindow) ,- } break,- case PageMenu_Format_75: /* Menu "Style Sheet. " */ { ViewSetStyleMap(xdWindow) ; } break; case PageMenu_Source: /* Menu "Show HTML..." */ { View 'view = (View *) xvt_vobj_get_data(xdWindow) ,- if ( vιew->wιnfo->source==NULL_WIN ) { if (( vιew->wιnfo->source = navι_xvt_wιn_create_res(Source, TASK_WIN, EM_ALL, Source_eh, xvt_vob3_get_data(xdWindow) ))==NULL_W IN) xvt_dm_pos _error("Can't open window"), ) i f ( vιew->wιnfo->source ' =NULL_WIN ) navι_vob3_raιse (vιew->wmfo->source) , ) break; case PageMenu_108_7 : /* Menu "NaviLinks . . . " * / { ViewAutoLink (xdWindow) ; ) break ; case PageMenu_Chk_Lιnks : /* Menu "Check Links . . . " * / ( {View "view = (View * ) xvt_vobj_get_data (xdWindow) , if ( vιew->wmfo->lιnks ' =NULL_WIN 1 navι_vob3_raιse (vιew->wmfo->lιnks ) ; else if ( ' (vιew->wιnfo->lιnks = navι_xvt_dlg_create_res (WD_MODELESS , HPPagaMn.c Tbu Mar 23 14:55:29 1995 7 ChkLnk, EM_ALL, ChkLnk_eh, (long) view))) xvt_dm_post_error("Can't open dialog") ; } } break; case PageMenu_108_116: /* Menu "Describe Page..." */ { AnyDescribe! ( (View *)xvt_vobj_get_data(xdWindow) )->page->url, false) ; ) break; case PageMenu_Searching: /* Menu "Search Server..." */ { AnySearch(xdWindow) ; ) break; case PageMenu_108_235_253: /* Menu "General..." */ { AnyAdmin(xdWindow) ; ) break,- case PageMenu_108_235_254: /* Menu "GET Cost..." */ ( ViewCosts(xdWindow, RUE) ; ) brea ; case PageMenu_108_235_247: /* Menu "PUT Cost..." */ { ViewCosts(xdWindow, ALSE) ; ) break; case PageMenu_108_235_248: /* Menu "POST Cost.." */ { ViewCosts(xdWindow,-1) ; ) break; case PageMenu_108_235_256: /* Menu "GET Permissions..." */ { ViewPermissions(xdWindow,TRUE) ,- ) break; case PageMenu_108_235_255: /* Menu "PUT Permissions..." */ { ViewPermissions(xdWindow, ALSE) ; ) break; case PagβMenu_108_235_215: /* Menu "POST Permissions..." */ ( ViewPermissions(xdWindow,-11 ; ) break; case PageMenu_108_13_16: /* Menu "General..." */ { if ( !navi_xvt_dlg_create_res(WD_MODAL, Prefs, EM_ALL, Prefs_eh, OL) 1 xvt_dm_post_error("Can't open dialog") ,- ) break; case PageMenu_108_13_34: /* Menu "Extensions/MIME..." */ { if (!navi_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_MIME) ) xvt_dm_post_error("Can't open dialog"),- ) break; case PageMenu_108_13_ 8: /* Menu "MIME/Viewer..." */ { MPPagaMn.c Tbu Mar 23 14 :55 : 29 1995 8 if ( ! navι_xvt_dlg_create_res (WD_MODAL , MIME , EM_ALL, MIME_eh, MIME_VIEWERS )) xvt_dm_post_error ( "Can ' t open dialog" ) . } break; case PageMenu_108_13_53- /* Menu "Save As Filters..." */ { if ( !navι__xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_SAVEAS) ) xvt_dm_poεt_error("Can't open dialog"),- ) break,- case PageMenu_108_13_137: /* Menu "MiniWeb Icons..." */ { f ( !navι_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_ICON) ) xvt_dm_poSt_error("Can't open dialog"), ) break; case PageMenu_108_13_142 • /* Menu "Naviservers " */ { if ( !navι_xvt_dlg_create_res(WD_MODAL, MIME, EM_ALL, MIME_eh, MIME_DESTINA TIONS) ) xvt_dm_post_error("Can't open dialog") ; ) brea ; case PageMenu_108_73: /* Menu "Delete..." */ { AnyDelete(xdWindow) ; ) break,- case PageMenu_Back: /* Menu "Backward" */ { ViewBack(xdWindow) ; ) break; case PageMenu_Foreward. /* Menu "Forward" */ { ViewForeward(xdWindow) ; ) break,- case PageMenu_Stop: /* Menu "Stop" */ { AnyStopCo (xdWindow) ,- } break; case PageMenu_ReloadPage: /* Menu "Reload Page* */ { ViewReloadCurrent(xdWindow) ; ) break,- case PageMenu_Go_79: /* Menu "Global History.. " */ { extern WINDOW history; if ( history'=NULL_WIN ) navι_vobj_raιse(history) ; else if ( !navι_xvt_dlg_create_res(WD_MODELESS, History, EM_ALL, Hιstory_eh , OD) xvt_dm_post_error("Can't open dialog") ,- ) break,- case PageMenu_107_124: /* Menu "Hot List..." */ { {extern WINDOW hotlist; if ( hotlis '=NULL_WIN) NPPagaMn.c Tbu Mar 23 14 :55 : 29 1995 9 navi_vobj_raise (hotlist ) ,- else i f ( ! xvt_win_create_res (HotList , TASK_WIN, EM_ALL, HotLιst_eh , OL) ) xvt_dm_post_error ( " Can ' t open window" ) ; ) ) break; case PageMenu_107_125 : /* Menu "Add To Hot List" */ { HotListAddCurrent(xdWindow) ,- ) break; case PageMβnu_92_93: /* Menu "Contents..." */ { LoadHelpWindowlNULL, "contents .htm" ) ,- ) break; caεe PageMenu_92_9 : /* Menu "Find..." */ { LoadHelpWindo lNULL, "helpsrch.htm" ) ,- ) break,- case PageMenu_92_99: /* Menu "FAQ..." */ { LoadHelpWindo lNULL, "faq.htm" ) ,- ) break,- case PageMenu_92_96 : /* Menu "Tutorial..." */ { LoadHelpWindowlNULL, "tutorial.htm* ) ; ) break,- case PageMenu_92_97 : /* Menu "Examples..." */ { LoadHelpWindo lNULL, "examples .htm" ) ; } break; case PageMenu_92_100: /* Menu "About HTML..." */ { CreatePageWinFor ! "http : / /www . nesa . uiuc . edu/General / Internet /WWW/HTMLPrimer . html " ) ,- ) break,- caεe PageMenu_92_101 : /* Menu "About URLs..." */ { CreatePageWinFor ( "http : / /www . nesa . uiuc . edu/demoweb/url -primer . html " ) ,- ) brea ; case PageMenu_92_103 : /* Menu "Tech Support..." */ { LoadHelpWindow(NULL, "techsprt.htm" ) ; ) break; case PageMenu_92_105 : /' Menu "About NaviPress ... " */ { if ( !xvt_win_create_res (AboutW, TASK_WIN, EM_ALL, AboutW_eh, OL) ) xvt_dm_post_error ( "Can' t open window" ) ,- ) break,- default: { if ( tag>=BOOKMARK_BASE it tag<=BOOKMARK_BASE+100 ) { /* The user selected something from the bookmark menu */ ViewBookmark(xdWindow, tag-B0OKMARK_BASE) ; } HPPagaMn.c Tbu Mar 23 14:55:29 1995 10 if ( tag>=WINDOW_MENU_BASE ti tag<=WINDOW_MENU_BASE+100 ) { /* The user selected something from the window menu */ ViewWindowRaise(tag-WINDOW_MENU_BASE) ; ) xvt_win_dispatch_event(TASK_WIN, xdEvent) ,- ) break,- NPM-Lln . c Wad Mar 22 16 : 11 : 37 1995 1 / * This file was generated by XVT-Design 3.0, a product of: XVT Software Inc. 4900 Pearl East Circle Boulder, CO USA 80301 303-443-4223, fax 303-443-0969 Generated on Wed Mar 22 16:11:37 1995 */ •include "xvt.h" •include "xvtcm.h" •include "NaviPres.h" /* Information about the dialog */ •define DLG_RES_ID NvLnk •define DLG_FLAGS OxOL •define DLG_CLASS "" •define DLG_MODE WD_MODELESS ♦include "func.h" /* Handler for dialog NvLnk ("SmartLinks" ) */ long XVT_CALLC0NV1 •if XVT_CC_PROTO NvLnk_eh XVT_CALLCONV2 (WINDOW xdWindow, EVENT "xdEvent) •else NvLnk_eh XVT_CALLCONV2 (xdWindow, xdEvent) WINDOW xdWindow; EVENT "xdEvent; •endif { short xdControlId = xdEvent->v.ctl.id; switch (xdEvent->type) ( case E_CREATE: /* Dialog haε been created; firεt event sent to newly-created dialog. */ { NvLnkFillup(xdWindow) ; ) break; case E_DESTROY: /* Dialog has been closed; last event sent to dialog. */ xdRemoveHelpAssoc( xdWindow ) ; { NvLnkDestroy(xdWindow) ,- } break; case E_FOCUS: { /* Dialog has lost or gained focus. */ if (xdEven ->v.active) { /* MPWvLink.c Wad Mar 22 16 :11 :37 1995 2 Dialog has gained focus V ) else { Dialog has lost focus break,- case E_SIZE: Size of dialog has been set or changed; sent when dialog is created or subsequently resized by xvt_vobj_move. break; case E_CLOSE: Request to close dialog; user operated "close* menu item on dialog system menu, or operated "close" control on dialog frame. Dialog not closed unless xvt_vobj_destroy is called. */ { xvt_vobj_destroy(xdWindow) ,- } break; case E_CHAR: Character typed. */ { } break,- case E_CONTROL: /- User operated control in dialog. switch(xdControlId) { case NvLnk_Apply: /* "Apply" */ { NvLnkApply(xdWindow) ,- ) break,- case DLG_163_PUSHBUTTON_21: /* "Done" { xvt_vobj_destroy(xdWindow) ; ) break; case NvLnk_Dismiss: /* "Cancel" */ { xvt_vobj_destroy(xdWindow) ; ) break; case NvLnk_Show: /* "Show Page" */ { NvLnkShowlxdWindow) ; } break; case NvLnk_Undo: /* "Undo" */ { NvLnkUndo (xdWindow) ,- MMtV ink . c Wad Mar 22 16 : 11: 37 1995 break; case DLG_163_PUSHBUTTON_20 : / * " Help" * / { HelpForWindow(xdWindow) ; ) break,- case NvLnk_Anchors: /* "List Box - Suggested Anchorε" */ { NvLnkChangeAnchor(xdWindow) ,- ) break; case NvLnk_URLs: /* "List Box - Possible Links" */ ( /* Liεt box waε operated. */ if (xdEven ->v.ctl.ci.v.lbox.dbl_clιck) NvLnkApply(xdWindow) , } else { single click ) ) break; default: break; ) ) break; case E TIMER: Timer associated with window went off. break; case E USER: Application initiated '/ ( switch (xdEvent->v.user.id) { case -1: default: break; } ) brea ; default: break; ) return OL; ▼iawadit.c Fri Mar 24 13:24:55 1995 1 /* Copyright 1994-1995 NaviSoft, Inc. All rights reserved */ •include <xvt.h> •include <toglbutn.h> •include <toolbar.h> •include "NaviPres.h" •include "func.h" •include "html.h" •include "view.h" •include "memmask.h" •include "doc.h" •include "xlocal.h" /* This is the guts of text editing, which boils down to taking one string out*/ /* of the page and replacing it with another. Of course we must also save */ /* the string that was in the page in an undo, and redraw all the affected */ /* windows */ struct bufinfo { char 'text, *tpt; mt tmax,- ); static void strstart (void) ; static void straddch PROTOTYPE((int)) , static void straddstr PROTOTYPE((char *)); static void straddstrn PROTOTYPE((char *, int)); static void straddnewline (void) ; static void straddend PROTOTYPE( (int) ) , static void straddtag PROTOTYPE((in ,char *)); static void CheckForVParaRemoved PROTOTYPE((View *, VPara *, int)); static void CheckForStuffRemoved PROTOTYPE((Page *, Para *, mt, ιnt)); static void FunkifyStuff PROTOTYPE((Page *, Para *, int, Para *)); static void RemoveAt PROTOTYPE! (Page *, Para *,Selection *,unsigned char *,ιnt,ιnt)), static void RemoveTagAt PROTOTYPE((Page *, Para *,Selection *,unsigned char *,ιnt)), static void SqueezeOutNoOps PROTOTYPE{(Page *,Para *,Selection *,Nestinfo *,ιnt,ιnt)), static void XVT_CALLCONVl ChangePara PROTOTYPE((Page *,Selection *, char *, nt.int)), static void XVT_CALLC0NV1 FindReplacement PROTOTYPE! (View *,Position *,VPara *,VPara *)), static void XVT_CALLC0NV1 RemoveVPara PROTOTYPE( (View ",VPara *,VPara *,ιntl); static int XVT_CALLC0NV1 CanDelete PROTOTYPE((Para *,mt)); static void XVT_CALLC0NV1 Re ovePara PROTOTYPE((Page *,Para *,Para *)), static void XVT_CALLC0NV1 RemoveVParas PROTOTYPE( (View *,Selection *,ιntl), static void XVT_CALLC0NV1 RemoveParas PROTOTYPE{{Page *,Selection *)); static int XVT_CALLC0NV1 ParaTagCanFollow PROTOTYPE! (int, Para ".Para *)),- static void InsertParaAfter PROTOTYPE((Para *, Para *, Page *)); static vo d InsertParaUnder PROTOTYPE((Para *, Para *, Page *, nt)l; static void InsertParaFirst PROTOTYPE((Para *, Page *,ιnt)), static Para * XVT_CALLCONVl _InsertParas(Page *, Selection *, Para *, Para *, unsigned cha r *, int, unsigned char *); static Para * XVT_CALLC0NV1 InsertParas PROTOTYPE((Page *,Selection *, nsigned char *, mt , unsigned char *)); static void XVT_CALLC0NV1 Change PROTOTYPE( (View ".Page *,Selection *, char *, t, intll; static int XVT_CALLC0NV1 AvoidNesting PROTOTYPE( (struct bufinfo *,mt,int,unsigned char ** , char *,in ) ) ; static int XVT_CALLC0NV1 ApplyTypeStyle PROTOTYPE((Para *,int, int, char *, char *)), static mt XVT_CALLC0NV1 RemoveTypeStyle PROTOTYPE((Para *, mt,int,int,int *)); static void XVT_CALLCONVl RemoveVParasTag PROTOTYPE((Page "page, intl); static void XVT_CALLC0NV1 RemoveParasTag PROTOTYPE((Page *, Para *)); static Para * XVT_CALLC0NV1 InsertParasTag PROTOTYPE((Page *, Para *, Para *,ιnt)), static void XVT_CALLC0NV1 InsertVParasTag PROTOTYPE) (Page *, VPara *, VPara *, Para "11, /' We begin with a set of routines that convert the selection into a string */ /* One for ascii text to export to naive clients, one for our weird parsed HTML*/ static char *selstr, viβwadit.c Fri Mar 24 13:24:55 1995 2 static unsigned int spos, smax, soff; static int fake_paras = false,- void XVT_CALLC0NV1 VieweditFakeParas(int fake 1 ( fake_paras = fake; ) static Para "newPara(void) ( Para "para = (Para *) myalloc(sizeof(Para) 1 ; para->text = myalloc(10) ; para->tmax = 9; para->tlen = 0; return para; ) static void strstart (void) { spos = 0; ) static void straddchϋnt ch) { if ( spos>=smax ) selstr = myrealloc(selstr,smax+=1024) ; selstr[spos++]=ch; } static void straddstr(char *str) { if ( str!=NULL ) while ( *str!='\0' ) { if ( spos>=smax ) selstr = myrealloc(selstr,smax+=1024) selstr[spos++]= *str++; } } static void straddstrn(char "str, int n) { while ( —n>=0 ) { if ( spos>=smax ) selstr = myrealloc(selstr,smax+=1024) ,- selstr[spos++]= *str++; } ) static void straddnewline(void) { •if XVT_OS_IS_WINOS straddch('\r' ) ; straddch('\n' ) ; •elif XVT_OS=«XVT_OS_MAC straddchC\r' ) ; •else εtraddch! '\n' ) ; •endif } static void straddendϋnt tag) { straddch(HTML_MARK) ; straddch(O) ; εtraddch(1) ; straddch(END_TAG) ,- straddch(tag) ; } static void straddtagϋnt tag, char *pt) { ▼iawadit .c Fri Mar 24 13 :24 : 55 1995 3 int len = 0 ; if ( pt ! =NULL 1 len = strlen (pt ) ,- s traddch ( HTML_MARK ) ; straddch (len/256 ) ; straddch (len%256 ) ,- straddch (tag) ,- i f ( pt ! =NULL ) straddstr ( t ) ,- } int XVT_CALLC0NV1 SelectionTransLen (void) { return ( spos ) ; } /* Translate the selection into an ascii string. Posibly including newlines */ /* possibly with HTML tags m it. There will always be a newline to mark the*/ /* end of a paragraph, there may be others to mark ends of lines (if crs is */ /* set) */ char * XVT_CALLC0NV1 Selectιon2Ascιι(View "v ew. Selection "sel, int crs, int html) { VPara *cur, "last; char *pt, "end; strstar () ; if ( sel->start.none ) return( "" ) ; cur = sel->start.para; if ( cur==NULL ti vιew'=NULL ) cur = vιew->first; if ( cur==NULL ) return( "" ) ; last = sel->end.para; pt = cur->para->text + sel->start.o fset; end = NULL; if ( crs ) for ( ι=0 ; κcur->lcnt-l it pt>cur->lιnes [i+l ] ; ++ι ) ; forever { i f ( pt ' =NULL ) { i f ( cur==last ) end = cur->para->text + sel->end.offset; while ( *pt'='\0' ) { if ( end!=NULL ti pt>=end ) break; if I crs it κcur->lcnt-l tt pt==cur->lιnes[i+l]-1 ) { straddnewlineI) ; ++i; ++pt; ) else if ( *pt'=HTML_MARK ) straddstr(LatιnlCharName(*(unsigned char *) pt++)), else if ( ((unsigned char *) pt) [HTML_POS_TAG]==ERROR_TAG ) /* Translate Nothing */ pt += Taglncr(pt) ; else if ( html ) { len = ((unsigned char *) pt) [HTML_LEN_HIGH] "256+ ( (unsigned char *) pt) [HTML_LEN_LOWJ , straddch('<'); if ( ((unsigned char *) pt) [HTML_POS_TAG]==END_TAG ) { straddch('/' ) ; straddstr(TagGetNa el ( (unsigned char *) pt) [HTML_END_TAG) ) ) ; ) else if ( ((unsigned char *) pt) [HTML_POS_TAG]==UNKNOWN_TAG 1 { straddstrn(pt-.HTML_HEAD_.LEN.len) ; ▼iawadit.c Fri Mar 24 13 : 24 : 55 1995 4 ) else { straddstr(TagGetName( ( (unsigned char *) pt) [HTML_POS_TAG] ) ) straddstrn(pt+HTML_HEAD_LEN,len) , } straddch('>'), pt += HTML_HEAD_LEN+len, } else pt += Taglncr(pt), ) } if ( cur==last ) break, while ( cur'=NULL tt cur'=last ) ( while ( cur'=NULL it cur->post==NULL tt cur'=last ) { if ( html tt cur->para->tag'=P_TAG ti TagNeedsTermmator(cur->para->tag) ) { straddstr("</") , straddstr(TagGetName! cur->para->tag )) straddch('>'), } straddnewlme() , cur = cur->parent, ) if I cur==NULL | | cur==laεt ) break; if ( html it cur->para->tag'=P_TAG it TagNeedsTermmator(cur->para->tag) ) ( straddstr("</") , straddstr(TagGetName! cur->para->tag )) straddch! '>' ) , } straddnewlme() , cur = cur->post, while ( cur'=NULL tt cur'=last ) { if ( html it ( cur->para->tag'=P_TAG | | 'cur->para->fake )) { straddch( '<' ) , straddstr(TagGetName( cur->para->tag )), if ( cur->para->tagtext'=NULL 1 straddstr(cur- para->tagtext1 straddch! '>' ) , ) if ( cur->subs==NULL ) break, cur = cur->subs, ) if ( cur->para->tex '=NULL 1 break, ) if ( cur«NULL ) break, pt = cur->para->text; ι = 0, ) straddch( '\0' ) , return! selstr ) ; ) /* Some tags have side effects Removing them removes a field, image, link, */ /* etc So we must update the data structures containing them as well */ static void CheckForVParaRemoved(View "view, VPara "vpara, int first) { t l Para "para = vpara ->para, for ( ι=0 ; κvιew->acnt , ) { if ( vιew->anchors [ I ] .para ' =para ) ▼iawadit.c Fri Mar 24 13:24:55 1995 5 ++i; else { if ( i ' =vιew->acnt-l ) memcpy(vιew->anchors+i,vιew->anchors+ι+1, (vιew->acnt-ι-l) 'sizeof (AnchorLis t)>; --view->acnt; ) ) for ( ι=0; κvιew->lcnt; ) { if ( view->1inks [ ] .para' =para ) ++i; else { if { first ) DocPageLostL nk (view->page, vιew->lιnks [ I ] . origname) ,- if ( l ! =vιew->lcnt-l ) memcpy (vιew->lιnks+ι , vιew->lιnks+ι+l , (vιew->lcnt-ι-l ) 'sizeof (LinkList ) ) ; --vιew->lcnt ; } ) if ( vpara->para->tag==FORM_TAG ) { for ( ι = 0 ; κvpara->f cnt ; *+ι ) VParaFreeFιeld(vpara->fιelds+ι , false) , DocPageLostLink (vιew->page, vpara- >para-> tagtext ) ; ) else { while ( vpara ' =NULL ) { for ( ι=0 ; κvpara->fcnt ; ) { if ( vpara->f ields [ι] .para ! =para ) ++i ; else ( | | vpara->fields [l] . type ==f_ιmagefleld) ) DocPageLostImageLιnk(vιew->page,vpara->fields [l] .ιmage-_-url) ; if ( l '=vpara->fcnt-l ) memcpy(vpara->fields+ι,vpara->fields-, i+l, (vpara->fcnt-ι-l) "sizeof ( VField) ) --vpara->fcnt; ) ) do vpara = vpara->parent; while ( vpara!=NULL it vpara->para->tag' =F0RM_TAG ); 5 /* Some tags have side effects. Removing them removes a field, image, link, "/ /* etc. So we must update the data structures containing them as well */ static void CheckForStuff emoved(Page 'page. Para "para, mt offset, int len) { View *vε; VPara *vp,- int first = true; for ( vs = page->vιewε; vε!=NULL; vs=vs->nextsame ) { if ( (View *) xvt_vob3_get_data (vs->w)==vs ) for ( ι=0; κvs->acnt; ) { if ( vs->anchors (I ] .para! =para | | vs->anchors [I] .o fset<offset ) ++ι; else if ( vs->anchorε [lJ .offset<offset+len ) { if ( l ' =vs->acnt-l ) memcpy(vs->anchors+ι ,vs->anchors+ι+1 , (vs->acnt-ι-l) 'sizeof (AnchorList) ); --vε->acnt,- ▼iawadit . c Fri Mar 24 13 :24 :55 1995 6 } else { vs->anchors [i] .offset -= len; ++ι; ) ) for ( 1=0; κvs->lcnt; ) { if ( vs->lιnks[ι] .para'-para | | vs->lιnks [ι] .offset<offset ) ++ι, else if ( vs->lιnks [l] .offset<offset+len ) ( if ( first ) DocPageLostLinklpage,vs->lιnks [l] origname) , if I ι'=vε->lcnt-l ) memcpy(vs->lιnks+ι,vs->lιnks+ι+l, (vs->lcnt-ι-l) "sizeof (LinkList) ) ; --vs->lcnt; } else { vs->lιnks (ι) .offset -= len, ++1, ) } vp = ViewGetVPara (vs,NULL,para->pnum) , while ( vp'=NULL ) { /* First remove any images, next time through loop remove fields */ /* No nested forms, so we exit after that */ for ( ι=0; κvp->fcnt; ) { if ( vp->fιelds[ι] .para'=para | | vp->fields [I] .offset<offεet ) ++ι, else if ( vp->fιelds[ι] .offset<offset+len ) { if ( first it (vp->fιelds [l] .type==f_ιmage | | vp->fields [i] type==f_ιm agefiβld) ) DocPageLostlmageLinktpage,vp->fields [I] .ιmage->url) , VParaFreeFιeld(vp->fιelds+1 , false) , if ( i ' =vp->fcnt-1 ) memcpy(vp->fιelds+ι,vp->fιelds+ι+l, (vp->fcnt-ι-l) "sizeof (VField) 1 —vp-> cnt; } else { vp-> ields [i] .offset -= len, ++ι; } ) do vp = vp---parent; while ( vp'=NULL it vp->para->tag' =F0RM_TAG } first = false, ) /" We sometimes act as though we are removing part of a paragraph that we are */ /* actually keeping. We need to preserve its fields, so make them have a */ /* funky paragraph (so CheckForStuff emoved won't delete them) */ static void FunkifyStu f (Page 'page. Para 'para, mt offset, Para 'topara) ( View *vs; VPara *vp, int i , for ( vs = page->vιews; vs'=NULL; vs=vs->nextsame ) { if ( (View *) xvt_vobj_get_data(vs->w) ==vs ) for ( ι=0; κvs->acnt, ++ι ) { if ( vs->anchors [ι) .para==para tt vs->anchors |ι] .offset>=offset ) { vs->anchors [l] .para = topara; vs->anchors [i] .offset -= offset, } ) for ( ι=0; κvs->lcnt, ++ι ) { if I vs->lmks [I] .para==para it vs->lιnkε[ι] offset>=offset ) { -iβwβdit.c Fri Mar 24 13:24:55 1995 7 vs->lmks[l] .para = topara; vs->lιnks[l] .offset -= offset; } ) if ( para'=NULL) vp = ViewGetVPara(vs,NULL, ara->pnum) ; else vp = ViewGetVPara(vs,NULL,topara->pnum) • while ( vp'-NULL tt vp->para->tag'=F0RM_TAG ) vp = vp->parent, if ( vp'=NULL ) { for ( 1=0; κvp->fcnt; ++ι ) { if ( vp->fιelds[i] .para==para it vp->fιelds[i] .offset>=offset ) { vp->fields[i] .para = topara; vp-> ields[l] .offset -= offset; } ) } ) ) /* Remove the two adjacent HTML tags that begin at pt One should be a start */ /* and one an end Adjust the offset in the selection to reflect this change*/ static void RemoveAt(Page "page, Para "para, Selection "sel, unsigned char "pt.mt len, in t ιs_undo) { int offset; offset = pt- (unsigned char *) para->text; UndoAddLitteral (page,ιε_undo,para->pnum,offset,para->pnum.offset,copyn( (const char *)p t.len)); memcpy(pt,pt+len,para->tlen+l-offset-len) , /* Include the NUL */ para->tlen -= len; if I para->tlen<0 ) { IError! "tlen negative in RemoveAt" ); para->tlen = 0; ) if ( sel->end.offset>of set+len ) sel->end.offset -= len, else if ( sel->end.offset>offset ) sel->end.offset = offset; if ( sel->start.offset>of set+len ) sel->start.of set -= len; else if ( sel->start.offset>offset ) sel->star .offset = offset; CheckForStuf emoved(page,para,offset,len) , ) /* Remove the two adjacent HTML tags that begin at pt One should be a start */ /* and one an end Adjust the offset in the selection to reflect this change*/ static void RemoveTagAt(Page *page. Para 'para. Selection *sel, unsigned char *pt, int ιs_ undo) { int len; len = 256*pt[HTML_LEN_HIGH]+pt[HTML_LEN_LOW]+HTML_HEAD_LEN; len += 256*pt[len+HTML_LEN_HIGH]+pt(len+HTML_LEN_LOW]+HTML_HEAD_LEN; RemoveAt(page,para,sel.pt,len,ιs_undo) ,- ) /* Walk through a paragraph looking for adjacent start/end (or end/start) tags*/ /* and remove them */ /* If offset is not 0, then don't remove noops that cross it */ static void SqueezeOutNoOps(Page "page. Para "para, Selection "sel, Nestinfo "ni, int offs unsigned char "pt = (unsigned char *) (para->text) , ▼iewedit.c Fri Mar 24 13:24:55 1995 8 unsigned char *npt; unsigned char Opt = pt+offset; int any; int preformatted = ParaPre ormatted(para) ; if ( page->dontsqueezenoops ) return; do { nι->ncnt = 0; any = 0; while ( *pt!='\0' ) { if ( *pt"HTML_MARK ) { if ( pt[HTML_POS_TAG]==END_TAG ) { npt = NULL; if ( pt[HTML_END_TAG]>=PARA_START ii pt[HTML_END_TAG]<=PARA_END ) /* Ignore it */; else if ( —nι->ncnt<0 ) { IError("Nesting screwed up in SqueezeOutNoOps" ) , ni->ncnt = 0; ) else npt = ni -> tagtext [m ->ncnt ] ; if ( npt ! =NULL ii npt + HTML_HEAD_LEN+ 256*npt[HTML_LEN_HIGH)+np IHTML_LEN_LOW)==pt it !TagHasWidth( (char *) npt) tt ! (pt<opt it npt>=opt) ) { /* Nothing between this and its start tag */ /* And it's not something like textarea which lε mean-*/ /* ingful even with no body */ RemoveTagAt(page,para,sel,npt,ιs_undo) ; any = true; pt = npt; ) elεe if ( np !=NULL tt pt(HTML_END_LE ]==HTML_MARK ti pt(HTML_END_LEN+HTML_POS_TAG)==ni->nestιng[nι->ncnt] it !TagHasWidth( (char *) pt) ti memcmp(npt,pt+HTML_END_LEN,256*np (HTML_LEN_HIGH]+npt[HTML_LEN _LOW] )==0 it ! (pt<opt tt npt>=opt) ) { /* Nothing between this and the following start tag, */ /* which happens to be the same as the last */ RemoveTagAt(page,para,sel,pt,ιε_undo) ; ++nι->ncnt; /* Back to where we were */ any = true; } else pt += HTML_HEAD_LEN+256'pt[HTML_LEN_HIGH]+pt[HTML_LEN_LOW] ; } else if ( TagNeedsTerm ator(pt(HTML_POS_TAG] ) ) { if ( nι->ncnt>=ni->nmax ) { nι->nestmg = (unsigned char *) myrealloc( (char *) nι->nestιng, ni ->nmax+=10 ) ,- ni->tagtext = (unsigned char **) myrealloc( (char *) ni- tagtext, n i->nmax*ειzeo (unsigned char **) ) ; } nι->nestιng(m->ncnt] = pt(3]; nι->tagtext(m->ncnt++] = pt; pt += HTML_HEAD_LEN+256'pt[HTML_LEN_HIGH}+pt[HTML_LEN_LOW] ; ) else pt += HTML_HEAD_LEN+256*ptIHTML_LEN_HIGH]+pt[HTML_LEN_LOW] ; } else if ( !preformatted it navι_ιsspaceI *pt ) ) I for ( npt= ++pt; navι_ιsspace(*npt) ; ++npt ) ,- if ( npt!=pt ) { RemoveA (page,para,sel,pt,npt-p , ιs_undo) ; any = true; ) } else viβwadit.c Fri Mar 24 13:24:55 1995 9 ++pt; ) ) while ( any ) , ) static void SqueezeOutNoOpAtEnds(View "view, int ιs_undo) { Selection sel, Nestinfo ni; memset(tni, '\0' ,sizeof(ni) ) ; if ( vιew->sel.start.para == view->sel.end.para ) { SqueezeOutNoOps(vιew->page,vιew->sel.start.para->para,tvιew->sel,tnι,0,ιs_undo) } else ( sel = vιew->sel; sel.end.para = sel.start.para; sel.end.offset = sel.start.para->para->tlen, SqueezeOutNoOps(view->page,vιew->sel.start.para->para,tsel,t , 0,ιs_undo) ; sel.start.para = vιew->sel.end.para; sel.start.offset = 0, sel.end.para = sel.star .para, sel.end.offset = vιew->sel.end.offset, SqueezeOutNoOps(vιew->page,vιew->sel.start.para->para,tsel,t , 0, ιs_undo) , vιew->sel.end.offset = sel.end.offset, ) myfree((char *) ni.nes ing), myfree( (char *) ni.tagtext); } static t IsAParentOf(VPara "parent,VPara 'para ) ( while ( parent'=para it para'=NULL ) para = para->parent, return para==parent; ) /* Translate the selection into a string with our parsed html in it */ /* We need to be careful that if we start the selection in the middle of an */ /* emphasis that we include the emphasiε (so "<B>thιs Λ ιε in* bold</B>" should*/ /* produce "<B> is ιn</B>" aε the string Paragraphs are more tricky, we do */ /* not want to include the paragraph mark for the first para We may also */ /* have an unbalanced number of para marks */ char * XVT_CALLC0NV1 Selectιon2Html(View "view, Selection "sel, t tagm) ( VPara "cur, "last; char *pt, 'end; int l,len; Nestinfo ni; strstart() ,- if ( sel->start.none ) return( "" ) ; cur = sel->start.para, last = sel->end.para; if I cur==NULL it vιew!=NULL ) { cur = vιew->fιrst; while ( cur'=NULL ) { if ( cur->para->tag'=P_TAG || 'cur->para->fake ) straddtag(cur->para->tag, cur->para->tagtext) ; if ( cur->subs==NULL | | cur==last ) break; cur = cur->subs, ) } if ( cur==NULL ) return( "" ) ; ▼iβwβdit .c Fri Mar 24 13 : 24 : 55 1995 10 soff = 0; if ( tagin ) { FindNesting(cur->para,sel->star .offset,tnι) ; len = HTML_HEAD_LEN+m . tagtex [ l ] [HTML_LEN_HIGH ] *2S6+m . tagtext I i ] [ HTML_LEN_LO W] straddstrnf (char *) m.tagtext[i] ,len) ; } soff = spos; ) pt = cur->para->text + sel->start.offset; end = NULL; forever { if ( pt!=NULL ) { if ( cur==last 1 end = cur->para->text + sel->end.offset; while ( *pt'='\0' ) { if ( end'=NULL ti pt>=end ) break; if ( *pt!=HTML_MARK ) straddch(*pt++1 ,- else { len = ((unsigned char *) pt) (HTML_LEN_HIGH)'256+ ((unsigned char *) pt) [HTML_LEN_LOW]+ HTML_HEAD_LEN, straddstrn(pt,len) , pt += len, } ) ) if ( cur==last ) { if ( tagin ) { ni.ncnt = 0; ..FindNestin (cur->para,sel->end.offset.tni) ; for ( i=nι.ncnt-l; i>=0; —i 1 straddend(ni.nes ing[i] 1 , ) break; ) while ( cur'=NULL ti cur!=last ) { while ( cur'=NULL it cur->post==NULL tt cur'=last 1 { /' We always terminate tags for internal use */ straddend(cur->para->tag) ; cur = cur->parent; ) if ( cur==NULL I I cur==last 1 break; /" We always terminate tags for internal use */ straddend(cur->para->tag) ; cur = cur->post; while ( cur'=NULL ) ( if ( cur->para->tag!=P_TAG || 'cur->para->fake ) straddtag(cur->para->tag, cur->para->tagtext) ; if ( cur->subs==NULL | | cur==last ) break; cur = cur->subs,- ) if ( cur->para->text'=NULL ) break,- ) break; ▼iβwadit.c Fri Mar 24 13 : 24 : 55 1995 11 pt = cur->para->text ,- ι = 0; } /* If a clear would delete this paragraph (merging it with a previous one)*/ /* we need to put in an indication of that fact by closing the para here */ while ( ! IsAParentOf (las ,sel->start.para )) { /' Do thiε even if the tag doesn't need a terminator... */ straddend(last->para->tag) ,- if I last->post!=NULL ) break; last = laεt->parent,- ) straddch! '\0' ) ; if ( tagin ) ( myfree! (char *) ni.nesting ) ,- myfree( (char *) ni .tagtext ) ; ) return! selstr ) ; ) /* Find out how much space the above routine will need */ int XVT_CALLC0NV1 IsSelectιon2HtmlTooLong(View "view. Selection *sel,mt tagin, long maxle n) { VPara *cur, "last; int i; long len; char *pt, "end; Nestinfo ni; if ( sel->start.none ) return( false ) ; cur = sel->start.para; if ( cur==NULL it vιew'=NULL ) cur = vιew->fιrst, if ( cur==NULL ) return( f lse ) ,- while ( cur->subs! =NULL ) cur = cur->subs; last = sel->end.para; len = 0; if ( tagin ) { FindNesting(cur->para, sel->εtart.offset, tni) , for ( ι=0; κnι.ncnt; ++ι 1 ( len += HTML_HEAD_LEN+nι .tagtext [l] [HTML_LEN_HIGH) *256+ . tagtex [l] [HTML_LEN_L OW) ; } ) pt = cur->para->text + sel->start.offset, end = NULL; forever ( if ( pt!=NULL ) { if ( cur==last ) end = cur->para->text + sel->end.offset; while ( *pt'='\0' ) { if ( end'=NULL ii pt>=end ) break; if ( 'pt '=HTML_MARK ) { ++len; ++pt; ) else { len += ((unsigned char *) pt) [HTML_LEN_HIGH] "256+ ((unsigned char *) pt) [HTML_LEN_LOW] + HTML_HEAD_LEN; viawβdit .c Fri Mar 24 13 :24 :55 1995 12 pt += Taglncr(pt) ; ) if ( len>=maxlen ) break; } ) if ( len>=maxlen ) break; if ( cur==last ) { if ( tagin ) { ni.ncnt = 0, _FιndNestmg(cur->para,sel->end.offset,t ) ; for ( =nι.ncnt-1; ι>=0; --ι ) len += HTML_END_LEN; ) break; ) while ( cur'=NULL ti cur'=last ) { while ( cur'=NULL tt cur->post==NULL tt cur'=last ) { len += HTML_END_LEN, cur = cur->parent; ) if ( cur==NULL I | cur==last ) break,- len += HTML_END_LE ; cur = cur->post; while ( cur'=NULL ti cur'=last ) { if ( cur->para->tag==P_TAG it cur->para->fake ) /" Do Nothing */; else if ( cur->para->tagtex '=NULL ) len += HTML_HEAD_LEN + strlen! cur->para->tagtext) else len += HTML_HEAD_LEN; if ( cur->subs==NULL ) break; cur = cur->subε; } if ( cur->para->text'=NULL ) break, ) ni.ncnt = 0,- if ( cur==NULL ) break; if ( len>-maxlen ) break; pt = cur->para->text; ι = 0; ) while ( ϋsAParentOf(last,sel->start.para )) { len += HTML_END_LEN; if ( last->post'=NULL ) break; last = last->parent, ) if ( tagin ) { myfree! (char *) ni.nesting ); myfree! (char *) ni. agtext ); ) return( len>=maxlen ) ; } void XVT CALLCONVl TermSelections (voιd> ( • viawadit.c Fri Mar 24 13:24:55 1995 13 myfree(selstr) ; } /*...........*.»..*..*..........*.., Editing *•«**»«««**•*•••*•****♦«*••***♦***/ /* Deleting a word should store the trailing space so that inserting it will */ /* restore the space... */ void XVT_CALLC0NV1 ViewTweakSelection(Selection 'sel.char *str, int len) { char *pt, 'end; int prev, so fset, eoffset,- int atstart, atend; if ( sel->start.para==NULL | | ParaPreformatted)sel->start .ρara->para) ) return; /* Don't mess with preformatted stuff. They think they know what they are doing */ pt = sel->end.para->para->text; if ( pt==NULL ) return; pt += sel->end.offset; while ( *pt==HTML_MARK tt !TagHasWidth (pt) ) pt += Taglncr(pt) ; if ( navi_isspace (*pt) ) eoffset = pt+1 - sel->end.para->para->text,- else eoffset = -1; prev = -1 ,- pt = sel->start .para->para->text; if ( pt==NULL ) return; end = pt + sel->start .of set; while ( pt<end ) { if ( *pt-=HTML_MARK ) pt += Taglncr(ptj ,- else { prev = '(unsigned char *) pt ; ++pt,- } ) if ( prev==-l | | navi_isspace(prev) ) soffset = pt - sel->star .para->para->text; else soffset = -1; if ( soffset==-l ti eoffset==-l ) return; else if ( soffset!=-l it eoffset!=-l it len== 0 ) { sel->end.offset = eoffset; return; } else if ( len==0 ) return; for ( pt=str; pt-str<len it !TagHasWidthlpt) ii pt! = '\0',- pt+=TagIncr (pt) 1 ; if ( pt-str>=len ) return; atstart = falεe; if < navi_isspace(*pt) ) atstart = true; atend = atstart; while ( pt-str<len ii *pt.' ='\0' ) { if ( navi_isspace(*pt) ) atend = true; else if ( TagHasWidthlpt) ) atend = false; viewed! t .c Fri Mar 24 13 :24 : 55 1995 14 pt += Taglncr (pt ) , ) if ( atstart it soffset ' =-1 ) sel->start . of fset = sof fset , if ( atend it eoffset ' =-1 ) sel->end. of f set = eoffset , ) • i f 0 static int ParalnsertText(Para 'para, mt off, char 'text, int len) { mt i, if ( para->tlen+len+l>-para->tmax ) para->text = myrealloc(para->text,para->tmax = para->tlen+len+10) for ( ι=para->tlen; ι>=off, --ι ) para->text[i+len] = para->text(i) , memcpy(para->text+off,text,len) , para->tlen += len, return! off+len ), ) •endif /* Within a paragraph, replace the text in the selection with the text in the *' /* string Leave the selection pointing at the end of the replacement */ /* We assume that str is a well formatted string (for every start tag there is*' /* an end tag) Our routines should ensure this */ static void XVT_CALLC0NV1 ChangePara(Page "page, Selection "sel, char "str, mt len int t yp g) { Para "para = sel->start.para->para, Nestinfo nι,nιend, int i, hlen, olen, epos, diff, nbase, elen, slen, char "pt, "end, 'base, 'endpt, 'reemph, int ch, if ( sel->start.para==sel->end.para ) epos = sel->end.offse , else epos = para->tlen, olen = epos-sel->start.offset, CheckForStuffRemoved(page,para,sel->start.offset,olen) ,- FindNesting(para,sel->start.offset.ini) , FindNesting(para,epos,tniend) ; if ( page->dontsqueezenoops ) ni.ncnt = 0; if ( page->dontsqueezenoops ) mend.ncnt = 0; for ( ι=nι.ncnt-1; ι>=0, --ι ) { if ( *str'=HTML_MARK ) break; hlen = ((unsigned char *) str) |HTML_LEN_HIGH) "256+( (unsigned char *) str) [HTML_LEN _LOW] ; if ( ((unsigned char *) str) [HTML_POS_TAG] == m.nestingli] tt hlen==0 tt ni.tagtext[l] [HTML_LEN_HIGH]*256+m. agtext[i] (HTML_LEN_LOW]==0 ) { str += HTML_HEAD_LEN+hlen; len -= HTML_HEAD_LEN+hlen; ) else break; } /* Count up the number of extra bytes we need to adjust nesting levels */ /* We need to close all open levels at the start, and open all levels */ ▼iawβdit.c Fri Mar 24 13:24:55 1995 15 /* at the end */ hlen = 0; nbase = 0; if ( typing /'it len'=0 */ ) { /* Typing goes in at current emphasis */ /' So the added text is at current, but we may be deleting emphasis */ /* changes (m'=nιend) so we need to fix up differences */ for ( nbase=0; nbase<nι.ncnt tt nbase<nιend.ncnt tt m.nestιng(nbase)==nιend.nesting[nbase] it strcmp! (char *) ni.tagtext[nbase] , (char *) mend.tagtex [nbase] )==0; ++nba se ) ; } else if ( len'=0 ) { /* Normal inserts go inside anchors */ for ( nbase=0; nbase<nι.ncnt it nbase<nιend.ncnt it ni.nesting[nbase]==A_TAG ti ni.nesting[nbase] [nbase] it strcmpt (char *) ni.tagtex [nbase] , (char *) mend tagtext[nbase] )==0, ++nba se ) ; « ) for ( ι=nbase; κnι.ncnt; ++ι ) hlen += HTML_END_LEN; elen = 0, for ( ι=nbase; Kniend.ncnt; ++ι 1 elen += mend,tagtext[l] [HTML_LEN_HIGH] *256+mend.tagtext[l] [HTML_LEN_LOW]+HTML_HE AD_LEN; /* Keep track of any nests we have to start (we can't do th s later because*/ /* end is relative to the current string */ ree ph = NULL; if ( elen'=0 ) { pt = reemph = myalloc(elen+1) ; for ( ι=nιend.ncnt-l; ι>=nbase ; --i ) { slen = mend.tagtext[l] [HTML_LEN_HIGH]*256+nιend.tagtext[1] [HTML_LEN_LOW]+ HTML_HEAD_LEN; memcpy(pt,mend,tagtext[i] ,slen) , pt += slen; } } hlen ♦= elen; /* Now here, hlen+len is the total number of characters we need to add */ /* and olen is the ones we will subtract */ /* Allocate enough space for the whole thing */ if ( para->tlen-olen+len+hlen >= para->tmax ) ( para->text = myrealloc(para->text, (para->tmax = para->tlen-olen+len+hlen+10)+1) , para->text[para->tlen]=' \0' ,- ) /* Move anything left at the end of the paragraph over */ base = para->text; diff = len+hlen-olen; if ( dιff<0 ) memcpy(base+epos+diff,base+epos,para->tlen+l-epos) , else if ( dιff!=0 ) { pt = base+para->tlen; end = base+epos; while (pt>=end) ( pt[dιff] = 'pt; — t; ) ) /* Copy the new stuff in */ pt = base+sel->start.of set; if ( typing it len'=0 ) { /* Typing goes in at current emphasis */ /* First the actual data */ memcpy(pt,str,len) , ▼iawβdit .c Fri Mar 24 13 : 24 : 55 1995 16 pt += len; endpt = pt; /* Now close anything that isn't open at the end */ for ( i=nbase; i<ni.ncnt; ++i ) { ch * pt[HTML_END_LEN] ; HTML_FillEndTag(pt,ni.nestin [i] ) ,- pt += HTML_END_LEN; *pt = ch; ) } else { /* First adjust the nesting */ for ( i=nbase; i<ni.ncnt; ++i ) { ch = pt[HTML_END_LEN] ; HTML_FillEndTag(pt,ni.nesting[i] ) ; pt += HTML_END_LEN; *pt = ch; » * ) /* Then the actual data */ memcpy(pt,str, len) ,- pt += len; endpt = pt; /* Then the end nesting */ } if ( reemph!=NULL ) { memcpy(pt,reemph,elen) ; /* Copy in reemphasiε εtuff */ pt += elen; my ree(reemph) ; ) para->tlen += diff; /* Mark the end of what we changed */ /* if commented out to backspace over LI */ •if 0 if ( sel->end.para==sel->start.para ) /* If not, change ends at eop */ •endif sel->end.offset = endpt-sel->star .para->para->text; sel->end.y = pt - sel->start.para->para->text; /* End offset for undo*/ /* Squeeze out adjacent start/end tags */ /'SqueezeOutNoOps(page,para,sel,tni, / *typing?endp -sel->end.para->para->text:* /0) ,-*/ myfree((char *) ni.nesting); myfree((char *) ni.tagtext) ,- myfree( (char *) niend.nesting) ; myfreeUchar *) mend,tagtext) ; 5 static void XVT_CALLC0NV1 RemovePara(Page 'page, Para 'prev, Para *cur) { if ( prev!=NULL ) prev->post = cur->post; cur->post = NULL; ParaListFree(cur) ; ) /* The paragraph containing the caret was just deleted. Find a new place to */ /* put the cursor (similarly for the selection) */ static void XVT_CALLCONVl FindReplacement(View 'view, Position *pos, VPara *prev, VPara *c ur) ( if ( prev!=NULL ) { poε->para = prev; pos->offset = (prev->para->text==NULL)?0:prev->para->tlen; ) else if ( cur->post!=NULL ) { pos->para = cur->post; pos->offset = 0; ) else ( viawβdit.c Fri Mar 24 13:24:55 1995 17 pos->para = view-> irst; pos->offset = 0; ) J static void XVT_CALLCONVl RemoveVPara(View 'view, VPara 'prev, VPara *cur, int first) { VPara *subs, *subnext,- if ( prev!=NULL ) prev->post = cur->post; CheckForVParaRemoved(view,cur,first) ; for ( subs = cur->subs; subs!=NULL; subs = subnext ) { subnext = subs->post; RemoveVPara(view,NULL,subs,first) ; ) cur->subs = NULL; /* VParaFree will attempt to free them again */ if ( view->caret.para==cur 1 FindReplacement(view,tview-.-care ,cur,prev) ,- if ( !view->sel.start.none ) { if ( view->sel.start.para==cur ) FindReplacement(view,tview->sel.start,cur,prev) , if I view->sel,end.ρara==cur ) FindReplacement(view,tview->sel.end,cur,prev) ,- ) VParaFree(cur, false) ; ) static int XVT_CALLC0NV1 CanDelete(Para 'para, int end) { if ( para->pnum<-end ) for ( para=para->firεt; para!=NULL tt CanDelete(para,end) ; para = para->post ); returnI para==NULL ) ,- ) /* Remove all vparas in the selection (except for the first one) */ static void XVT_CALLC0NV1 RemoveVParas{View "view, Selection "sel, int first) { VPara 'prev, *cur, 'post; int end = sel->end.para->para->pnum; prev = ViewGetVPara(view,NULL,sel->start.para->para->pnum) ,- delete_nested: if ( prev->subs!=NULL 1 { for ( cur=prev->subs; cur!=NULL tt CanDelete(cur->para,end) ; cur = post ) { post = cur->post; RemoveVPara(view,NULL,cur, first) ; prev->subs = post; ) if ( cur!=NULL it cur->para->pnum<=end ) { prev = prev->subs; goto delete_nested; } ) forever { for ( cur=prev->post; cur.'=NULL it CanDelete(cur->para,end) ; cur = post ) { post = cur->post; RemoveVPara(view,prev,cur,first) ; ) if ( cur==NULL ) { prev = prev->parent; if ( prev==NULL ) break; } else if ( cur->para->pnum>end ) break; else ( prev = cur; /* Last thing to delete iε within */ goto delete_nested; ) ) ▼iawadit .c Fri Mar 24 13 : 24 : 55 1995 18 ) /* Remove all paragraphs in the selection except for the first one (yes, */ /* remove the last one too. We do weird t funky stuff to make this work) */ /* This is practically identical to RemoveVParas. We have parallel data */ /* structures and must keep them in sync. The only reason for not doing */ /* both together in the same routine is that there is a many to one mapping * /* of para to vparas */ static void XVT_CALLC0NV1 RemoveParas(Page "page. Selection "sell ( Para "prev, *cur, 'post; mt end = sel->end . para->para->pnum; View *vs ; prev = sel->start.para->para; for ( vs=page->vιews; vε'=NULL; vε=vε->nextsame 1 ( if ( (View *) xvt_vob _get_data(vs->w)==vs ) RemoveVParas(vs,sel,vs==page->vιews) , vε->cheat = NULL; ) delete_nested: if ( prev->fιrst!=NULL ) { for ( cur=prev->first; cur!=NULL tt CanDelete(cur,end) ; cur = post ) { post = cur->post; RemovePara(page,NULL,cur) ,- prev->fιrst = post; ) f ( cur==NULL I I cur->pnum<=end 1 { prev = prev->first; goto delete_nested; ) ) forever { for ( cur=prev->post; cur'=NULL it CanDelete(cur,end) ; cur = post ) ( post = cur->post; RemovePara(page,prev,cur) ,- ) if ! cur==NULL ) ( prev = prev->paren , if ( prev==NULL ) break; ) else if ( cur->pnum>end ) break; else { prev = cur; /* Last thing to delete is within */ goto delete_nested; ) ) ) static int ParaTagCanFollowdnt tag. Para "prev. Para "parent) { if ( parent==NULL ) parent = prev->parent; if ( parent«NULL | | (parent->tag'=0L_TAG ii parent->tag!=UL_TAG it parent->tag!=DL_TAG) ) return) tag'=LI_TAG ti tag!=DD_TAG it tag!=DT_TAG ); if ( tag==UL_TAG | | tag==OL_TAG | | tag==DL_TAG ) return( true 1 ; return! tag==LI_TAG | | tag==DD_TAG | | tag==DT_TAG ); ) static void InsertParaAfter(Para "para, Para "prev. Page "page) ( View "vs; VPara "vpara, "vprev. ▼iβwadit.c Fri Mar 24 13:24:55 1995 19 for ( vs = page->views; vs!=NULL; vs=vs->nextsame ) { if ( (View *) xvt_vobj_get_data(vs->w)==vs ) { if { vs->chea !=NULL it vs->cheat->para==prev ) vprev = vs->cheat; else vprev = VParaOf(vs,prev) ; if { vprev==NULL ) IErrorI"vprev==NULL in InsertParaAfter") ,- else { vpara = (VPara *) myalloc(sizeof(VPara) ) ; vpara->para = para; vpara->post = vprev->post; vprev->post = vpara; vpara->parent = vprev->parent; ) vs->cheat = vpara; ) ) } static void InsertParaUnder(Para 'para, Para 'parent. Page 'page, int needsfixup) { View *vs; VPara 'vpara, 'vpar; for ( vs = page->views; vs!=NULL; vs=vs->nextsame ) { if ( (View *) xvt_vobj_get_data(vs->w)==vs ) { if ( vs->cheat!=NULL tt vs->cheat->parβ==parent ) vpar = vs->cheat; else vpar = VParaOf(vs,parent) ,- if ( vpar==NULL ) IError("vpar==NULL in InsertParaUnder"); else { vpara = (VPara *) myalloc(sizeof(VPara) ) ; vpara->para = para; vpara->post = vpar->subs; vpar->subs = vpara; vpara->parent = vpar; vpara->y = vpar->y; if ( needsfixup ) ( metricParalndent(vs,vpara) ; if ( vs->sel.start.para->para=-parent ) vs->sel.start.para = vpara; if ( vs->sel.end.para->para==parent ) vs->sel.end.para = vpara; if ( vs->caret.para->para-=parent ) vs->caret.para = vpara; ) } vs->cheat = vpara; } ) ) static void InsertParaFirst(Para 'para, Page 'page, int needsfixup) ( View *vs; VPara 'vpara; for ■( vs = page->views; vs!=NULL; vs=vs->nextsame ) ( if ( (View *) xvt_vobj_get_data(vs->w)==vs ) { vpara = (VPara *) myalloc(sizeof(VPara) ) ; vpara->para = para; vpara->post = vε->first; ▼iβwβdit.c Fri Mar 24 13:24:55 1995 20 vs->first = vpara; vs->cheat = vpara; if ( needsfixup ) { metricParalnden (vs,vpara) ; if I vs->sel.start. ara==NULL ) vs->sel.start.para = vpara; if ( vs->sel.end.para==NULL ) vs->sel.end.para = vpara; if ( vs->caret.para==NULL ) vs->caret.para = vpara, ) ) ) ) static int UnendedPara(unsigned char 'parastr) { int para_depth = 0; int len,- do { if ( parastr[0)==HTML_MARK ti TaglsPara(parastr[HTML_POS_TAG] ) ) { ++para_depth; len = 256"parastr[HTML_LEN_HIGH]+ parastr[HTML_LEN_LOW] ; parastr += HTML_HEAD_LEN+len; ) else if ( parastr[0]==HTML_MARK tt parastr[HTML_POS_TAG]==END_TAG tt TaglsPara(parastr[HTML_END_TAG] ) ) { parastr += HTML_END_LEN; —para_depth; ) else if ( parastr[0)==HTML_MARK ) { len = 256*parastr[HTML_LEN_HIGH)+ parastr[HTML_LEN_LOW] ; parastr += HTML_HEAD_LEN+len; } else ++parastr; } while ( 'parastr!='\0' it para_depth!=0 ); return para_depth>0,- ) static Para 'MergelntoPara(Page 'page, Selection *sel. Para 'para,unsigned char 'parastr,u nsigned char 'end, unsigned char 'endstr) ( while ( parastr[0]==HTML_MARK ii para->first!=NULL it ((unsigned char *) parastr) [HTML_POS_TAG]==para->first->tag tt TagText atches( (char *) parastr,para->first) tt UnendedPara(parastr) ) { para = para->first; parastr += Taglncr( (char *) parastr); ) return! _InsertParas(page,sel,para,NULL,parastr,end-parastr,endstr) ) ; ) static Para * XVT_CALLC0NV1 _InsertParas(Page 'page. Selection *sel. Para "parent, Para *p rev, unsigned char 'parastr, int paralen, unsigned char 'endstr) ( Para "hra , *hp; int tag, len; char *tagtext; unsigned char "start; unsigned char 'end = parastr+paralen; Para 'para = prev; while ( 'parastr tt parastr<end ) { if ( parastr(0)==HTML_MARK it parastr[HTML_POS_TAG)==END_TAG ) parastr += HTML_END_LEN; hmm = prev; hp = parent; ▼iawβdit .c Fri Mar 24 13 :24 :55 1995 21 while ( parastr [ 0 ) ==HTML_MARK ii parastr [HTML_POS_TAG] ==END_TAG ii hp ! =NULL it (hmm==NULL | | hmm->post==NULL ) ) { if ( hm == NULL ) { hmm = hp ; ) else { hmm = hmm->parent; ) if ( hm_n!=NULL ) hp = hmm->parent; parastr += HTML_END_LEN; } While ( parastr[0]==HTML_MARK ti parastr[HTML_POS_TAG]==END_TAG ) parastr += HTML_END_LEN; if ( *parastr=='\0' || parastr>=end ) brea ; if ( parastr[0]==HTML_MARK it hmm!=NULL ti hmm->post!=NULL it parastr[HTML_POS_TAG]==hmm->post->tag it TagTextMatches{ (char *) parastr,hmm->post) it UnendedPara(parastr) ) { return! MergelntoPara(page,sel, hmm->poε .parastr+Taglncr( (char *) parastr), end,endstr) 1 ,- ) TryNextPara: tag = P_TAG; tagtext = NULL; if ( parastr[0)==HTML_MARK tt TaglsPara(parastr[HTML_POS_TAG] ) ) ( tag = parastr[HTML_POS_TAG] ; len = 256*parastr[HTML_L__N_HIGH]+ parastr[HTML_LEN_LOW] ; if ( len>0 ) tagtext = copynUchar *) parastr+HTML_HEAD_LEN,len) ,- parastr += HTML_HEAD_LEN+len; ) /* The number of END marks we got is not trust-worthy, we may not be */ /* in a situation where we can use them */ prev = hmm; parent = hp; if ( parent!=NULL tt parent->tag>=DIR_TAG ii parent->tag<PLISTTAG_START ) ( if ( tag==UL_TAG | | tag==OL_TAG | | tag==DL_TAG ) /* Lists can nest */,- else if ( parent->tag == DL_TAG ) { if ( tag==DD_TAG | | tag==DT_TAG ) { /* Leave as is */; ) else if ( prev==NULL | | prev->tag==DD_TAG ) tag = DT_TAG; else tag = DD_TAG; ) else if ( parent->tag!=DL_TAG ) tag = LI TAG; ) if ( !ParaTagCanFollowftag,prev,parent) tt (tag==LI_TAG || tag==DD_TAG || tag==DT_TAG) ) { /* If we aren't in a list, then ignore the list items, there will */ /* be a real paragraph inside */ goto TryNextPara,- ) if ( !ParaTagCanFollowftag,prev,parent) 1 tag = P_TAG; /* Ug. We've finally got a place to put our paragraph and an accept- */ •/* able type for it. Now figure out the body of the paragraph */ for ( start = parastr; 'parastr ; parastr += Taglncr( (char *) parastr)) { if ( 'parastr==HTML_MARK ii (TaglsPara(parastr[HTML_POS_TAG] ) | | (parastr[HTML_POS_TAG]==END_TAG ii TaglsPara(parastr[HTML_END_TAG] ) )) viβwβdit.c Fri Mar 24 13:24:55 1995 22 break; ) /* And create it */ para = (Para • ) myalloc(sizeof(Para) ) ,- if ( prev!=NULL ) { para->post = prev->post; prev->post = para; para->parent = prev->parent; InsertParaAfter(para,prev,page) ; } else if ( parent!=NULL ) { para->post = parent->first; parent-> irst = para; para->parent = parent; InsertParaUnder(para,parent,page,false) ; } else { para->post = page->first; page->first = para; InsertParaFirst(para,page, false) ,- ) para->tag = tag; para->tagtext = tagtext; para->fake = fake_paras tt ParaPreformatted(para1 ; if ( tag!=P_TAG ) { tag = P_TAG; parent = hp = para; prev = hmm = NULL; parastr = start; goto TryNextPara; } else if ( parastr>=start ) { para->text = copynUchar *) start,parastr-start) ; para->tlen = para->tmax = parastr-start; } else if ( tag==P_TAG ) { para->text = myalloc(lθ); para->tmax = 9; para->tlen = 0; } if ( tag>=PARA_START tt tag<=PLISTTAG_END ) { prev = NULL; parent = para; } else prev = para; ) /* Keep track of where we finished */ sel->end.offset = para->tlen; sel->end.y = para->tlen; /' Now we may need to add to the final paragraph the bit at the end of */ /* last para in the selection which was not selected (we deleted this */ /* earlier) */ if ( endstr!=NULL tt 'endstr!='\0' 1 { len = HTML_len( (char *) endstr); if ( len+para->tlen>=para->tmax ) para->text = myrealloc(para->text,para->tmax = len+para->tlen+10) ; memcpy(para->text+para->tlen,endstr,len+1) ; /* Copy trailing NUL */ para->tlen += len; ) return( para ) ; ) static Para * XVT_CALLC0NV1 InsertParas(Page "page. Selection "sel, unsigned char "parastr , int paralen, unsigned char "endstr) { Para "prev = sel->start.para->para; return ( _InsertParas(page,sel,prev->parent,prev,parastr,paralen,endstr) ) ; viawadit.c Fri Mar 24 13 :24 :55 1995 23 ) /' We removed some paragraphs, or added some, or something like that */ /* Anyway they need to run in a good sequence again */ void XVT_CALLC0NV1 RenumberParas(Page 'page) { int pnum =0; Para 'para = page->first; while ( para!=NULL ) { para->pnum = pnum++; if ( para->first!=NULL ) para = para-> irst; else if ( para->post!=NULL ) para = para->post; else { while ( para.'=NULL &i»para->post==NULL ) para = para->parent; if ( para!=NULL ) para = para->post; ) ) ) /* Given a string and a selection, replace the selection with the string */ /* Complications: Either the string or the selection may stretch over multiple*/ /* paragraphs */ static void XVT_CALLC0NV1 Change(View 'view, Page 'page, Selection *sel, char *str, int le n, int typing) { unsigned char *pt; int any_paras, i; Selection temp; char *end_str=NULL; Para 'endp; int real_soff; • forever { any_paras = -1; for ( pt=(unsigned char *) str; *pt; pt += Taglncr((char *) pt) ) if ( *pt==HTML_MARK tt (TaglsPara(p [HTML_POS_TAG] ) || ' (pt[HTML_POS_TAG]==END_TAG tt TaglsPara(pt[HTML_END_TAG] ) )) ) ( any_paras = (char *) pt-str; break,- ) /* We can't have text sitting directly in various kinds of paras */ /* so if we find a list with no list items, create a list item before*/ /* anything else */ if ( sel->start.para==NULL ) { /* No text */ int tag = P_TAG; if ( any_paras-=0 ) { while ( p [0)-«HTML_MARK ti pt[HTML_POS_TAG]==END_TAG ) { Str += HTML_END_LEN; pt ♦= HTML_END_LEN; len -= HTML_END_LEN; } if ( pt{HTML_POS_TAG] !=END_TAG ) { tag = pt [HTML_POS_TAG] ; i = Taglncr(str) ,- εtr += i; len -= i; ) ) endp = page->first; page->first - newPara(1 ,- ▼iawadit.c Fri Mar 24 13:24:55 1995 24 page->first->post = endp; page->first->tag = tag; InsertParaFirst(page->first.page,true) ; sel->start.para = page->views->first; if I sel->end.para==NULL ) sel->end.para = sel->start.para; RenumberParaε(page) ; } else if ( sel->start.para->para->tag>= PARA_START ii sel->start.para->para->tag<=PLISTTAG_END ii sel->start.para->para->first==NULL ) { int tag = P_TAG; if I sel->start.para->para->tag==DL_TAG 1 tag = DT_TAG; else if ( sel->start.para->para->tag<PLISTTAG_START 1 tag = LI_TAG; if ( any_paras==0 ii (tag==pt(HTML_POS_TAG) || tag==P_TAG) ) ( tag = pt[HTML_POS_TAG] ; i = Taglncr(str) ; str += i; len -= i; ) endp = sel->start.para->para; endp->first" = newPara() ; endp->first->tag = tag; endp->first->parent = endp; InsertParaUnder(endp->firεt,endp,page,true) ; if ( sel->end.para == sel->start.para it sel->end.para->para==endp ) sel->end.para = sel->start.para->subs; if ( sel->start.para->para==endp ) sel->start.para = εel->start.para->subs; RenumberParas(page) ; } else break,- ) /* Do the simple, common case */ if ( sel->start.para==sel->end.para tt any_paras==-l ) { ChangePara(page,sel,str,len, typing) ; sel->end.x = sel->start.para->para->pnum; /* store para # because vpara may change */ return,- ) if ( sel->start.offset==0 tt any_paras==0 ) { /* Special case! ! ! ! insert new paras in front of this one ! ! ! */ ) /* Grab the end of the last paragraph, life is easier if we delete it and */ /* then add it back */ real_soff = 0; if ( sel->end.offset < sel->end.para->para->tlen ) { FunkifyStuff(page,sel->end.para->para,sel->end.offset.NULL) ; temp.start = sel->end; temp.start.none = false; temp.end = sel->end; temp.end.offset = sel->end.para->para->tlen; end_str = Selection2Html(view,ttemp, !view->page->dontsqueezenoops) ; real_soff = soff; sel->end = temp.end; ) /* Change the first paragraph */ ChangePara(page,sel,str,any_paras==-l?len:any_paraε, typing) ; /* Remove any paragraphs between the start and the end paragraph */ ▼iβwβdit.c Fri Mar 24 13:24:55 1995 25 /* if the start para is not the same as the end para, then remove the end*/ RemoveParas(page,sel) ; /* Insert any new paragraphs we need */ endp = sel->start.para->para, if ( any_paras'=-1 ) endp = InsertParas(page,sel, (unsigned char *) str+any_paras, len-any_paras, (unsigned char *) end_str) , else if ( end_str!=NULL ) { temp,start.para = sel->start.para.- temp.start.offset = temp.star .para->para->tlen, temp.start.none = false, temp.start.pmapped = true; temp.start-mapped = false, temp,end = temp,start,- ChangePara(page,itemp,end_str,HTML_len(end_str) ,false) , sel->end = temp,start,- sel->end.y = sel->end.offset, sel->end.pmapped = true, sel->end. apped = false; ) sel->end.y += real_soff, /* End for Undo */ if ( end_str'=NULL ) { FunkifyStuff(page,NULL,-sel->end.o fset,endp) , #ιf 0 myfree(end_str) , /* We never copied it, 3ust liveε in Select buffer */ •endif ) RenumberParas(page) ; sel->end.x = endp->pnum; /* store para # because vpara may have changed*/ ) void XVT_CALLC0NV1 ViewDoChange(View "view, char *str, mt len, int ιε_undo, mt typing, l nt redraw, int keep_undo) ( char 'undostr; int psnum; Undo "base = ιs_undo , vιew->page-_»redoes:vιew--»page->undoeε, if ( 'ViewInsertFieldCheck(view,str,len) ) return; if ( vιew->sel.start.none ) { vιew->sel.start = vιew->caret, view->sel.end = vιew->caret, ) ViewUndrawSel(view,tvιew->sel) , ViewTweakSelection(ivιew->sel,str,len) ; /" We get rid of stale anchor, links, fields as we go along */ /" We add new ones when we get to the metrics */ if ( !keep_undo ) { undostr = NULL; •ifdef MEMORY_MASK ) else if ( IsSelectιon2HtmlTooLong(vιew,ivιew->sel, alse,MEMORY_MASK-1500) ) ( if ( navι_dm_post_ask(Vιewιns_Procede/*"Procede**/,General_Cancel/*"Cancel"*/.NULL _RID, Vιewms_CantUndo/*"Warning This operation cannot be undone Procede anyw ay'"*/) '=RESP_DEFAULT ) ( ViewDrawSel(vιew,tvιew->sel) ; return; ) UndoFree!view->page---undoes) ; UndoFree(vιew->page->redoes) , xvt_menu_set_ιtem_enabled(vιew->w,PageMenu_Redo, alse) , xvt_menu_set_ιtem_enabled(vιew->w,All_Undo, alse) ; vιew->page->undoeε = NULL; vιew->page->redoes = NULL, undostr = NULL; •endif ▼iewadit.c Fri Mar 24 13:24:55 1995 26 } else { undostr = Selectιon2Html(view,tvιew->sel, false) , undostr = copyn(undostr,SelectionTransLenl) ) ; ) if ( redraw ) SaveWhatlnfoWeNeedForRedraw(vιew->page,tvιew->sel) ; if ( vιew->sel.start.none ) { vιew->sel.start = vιew->caret; vιew->sel.end = vιew->caret; vιew->sel.start.none = true; } else vιew->sel.start.none = true; /* we don't want it to show when we displa V */ psnum = -1; if ( vιew->sel.start.para'=NULL ) psnum = vιew->sel.start.para->para->pnum; Change(view,view->page,tvιew->sel,str, len, yping) ; if ( undostr'=NULL ) (typing ScSc 'is.undo'UndoAddTyping:UndoAddLitteral) (vιew->page,ιs_undo, psnum, vιew->sel.start.of set, vιew->sel.end.x,vιew->sel.end.y,undostr) ; /' Squeeze out adjacent start/end tags */ vιew->sel.end.para = ViewGetVPara(view,vιew->sel.start.para,vιew->sel end.x); SqueezeOutNoOpAtEnds(view,ιs_undo) ,- UndoλddMultiple(vιew->page,ιs_undo, ase) ; if ( redraw ) ReMetricEverythingChanged(vιew->page,tview->sel) , vιew->caret = vιew->sel.end; view->caret.mapped = false, view->caret.pmapped = true, vιew->sel.start.none = true; PageSetChanged(view->page,true) ; if ( redraw ) RedrawEverythιngChanged(vιew->page,tvιew->εel,true) , ) void XVT_CALLC0NV1 ViewChange(View 'view, char *εtr, int len, mt ιs_undo, int typing) { ViewDoChange(view,str,len, ιs_undo, typing,true,true) , ) /* If the first para of the selection is NULL then we need to insert a blank */ /* para in front of it */ void XVT_CALLC0NV1 ViewInitialCheck(View "view) { Selection sel; if ( vιew->sel.star .none ) { if ( vιew->care .para'=NULL ) return, sel.start.none = true; ) else if ( view->sel.start.para!=NULL ) return; else { vιew->sel.start.para = vιew->fιrst; vιew->sel.start.offset = 0; vιew->sel.start.mapped = false; vιew->sel.start.pmapped = true, return; } vιew->sel.start.none = true; vιew->caret.para = NULL; vιew->caret.offset = 0; ViewChange(view, "" , 0, false, false) ; riawadit.c Fri Mar 24 13:24:551995 27 if ( sel .start .none ) ( vιew->caret .para = vιew->fιrst; vιew->caret . of f set = 0; } else { view->sel = sel; view->sel.start.para = vιew->first->poεt,- view->sel.star .offset = 0; } } /.._._...,..___....._.._..,...« Dra g an< j D rθ p *»*♦*♦«♦♦«+•»• • •*•♦*♦*••♦«♦*♦*•••/ /* Move the selection to where the cursor now is (copy it, delete it, paste) */ void XVT_CALLC0NV1 ViewDropIt(View "view, EVENT "event) { char 'oldstr, *pt; int len, off=0, ιn_end=false; Position pos; Selection sel; PNT from; struct undo 'base = vιew->page->undoes; View 'newview; /* What view did they drop into */ from = event->v.mouse.where; xvt_vobj_translate_pomts(vιew->pane,SCREEN_WIN,ifrom, 1) ; newview = ViewWiπFindViewlview, from.h, from.v) ,- if ( newview==NULL || newvιew->tag '= TAG_VIEW ) newview = view; if ( newview!=vιew ) xvt_vobj_translate_points(view->pane,newview->pane,tevent->v. ouse.where, 1) if ( ViewReadOnly(newview) ) return; /' We need to figure out where the insertion point is NOW because the */ /* mapping between screen and internal will change after the delete */ pos.x = event->v.mouse.where.h + newvιew->text_offleft; pos.y = event->v.mouse. here.v + newvιew->text_offtop; pos.mapped = false; pos.pmapped = false; ViewMapScreen(newview,tpos,true) ; if ( pos.para!=NULL tt pos.para->para==vιew->sel.end.para->para it pos.offset>=vιew->sel.end.offset ) { ιn__end = true; pt = pos.para->para->text + vιew->sel.end.offse ; if ( pt!=NULL ) while ( *pt==HTML_MARK tt !TagHasWidth(pt) ) pt += Taglncr(pt) ; if ( pt-pos.para->para->text>pos.offset ) off = 0; else off = pos.offset- (pt-pos.para->para->text) ; ) oldstr = Selection2Html(view,tvιew->sel,true) ,- /* copy */ oldstr = copyn(oldstr,len = SelectionTransLenf) ) ; if ( !event->v.mouse.control ) ViewChange(view, "",0,false,false) ; /* delete */ else vιew->caret = vιew->sel.end; if ( ιn_end ) { if ( vιew==newview ) pos.para = vιew->caret.para; else pos.para = ViewGetVPara(newview,NULL,vιew->caret.para->para->pnum) ,- pt = pos.para->para->text + vιew->caret.offset; while ( *pt==HTML_MARK ii !TagHasWidth(p ) ) ▼iβwβdit.c Fri Mar 24 13:24:55 1995 28 pt += Taglncr(pt), pos.offset = (pt - pos.para->para->text) + off, ) pos.mapped = false; pos.pmapped = true; ViewMapPosition(newview,tpos) ; if ( pos.para'=NULL ii pos.offset>pos.para->para->tlen ) { IError("DragtDrop offset wrong"), return; ) sel.start = pos; sel.start.none = true, sel.end = poε; ViewUpdateSel (newview,tsel) , newview->caret = pos, ViewChange(newview,oldstr,len-1,false, false) ,- /* len includes the NUL, w e don't want it */ UndoAddMultiple(vιew->page,false,base) ; ) /............................... τyp e styles *** •• **** •• * « *** ••»» * •• * » **** « * ••• / static int AvoidNest g(struct bufinfo *ιnfo, int nlevel, mt base, unsigned char **tagtex t, char 'endstr, int elen) { char 'text = ιnfo->text, *tpt = ιnfo->tpt; int tmax = ιnfo->tmax, int off, ret; int len, /* At this point, any internal unmatched ENDs have been dealt with */ /* But we still have to worry about any thing nested */ /* First end them */ if ( (HTML_END_LEN+HTML_HEAD_LEN)*(nlevel-base)+elen+(tpt-text)+l>=tmax ) ( off = tpt-text; text = myrealloc(text,tmax = (HTML_END_LEN+HTML_HEAD_LEN) "nlevel+elen+off+10) , tpt = text+off; ) for ( ι=nlevel-l, ι>=base, --ι ) ( tpt[0] = HTML_MARK; tpt(HTML_LEN_HIGH]=0, tpt[HTML_LEN_LOW]=1; tp [HTML_POS_TAG]= END_TAG; tpt[HTML_END_TAG]= tagtex [l] [HTML_POS_TAG] , tpt += HTML_END_LEN, } memcpy( pt,endstr,ele 1 , tpt += elen, ret = tpt-text; /* Now start them up again. We must do things in this funky way */ /* in order to make sure things nest properly */ for ( ι=base; κnlevel; ++ι ) { len = tagtext[i] [HTML_LEN_HIGH]*256+ tagtext[i] [HTML_LEN_LOW]+HTML_HEAD_LEN; if ( tpt-text+len+1 >= tmax ) { off = tpt-text; text = myrealloc(text,tmax += len+10) ; tpt = text+off; ) memcpy(tpt,tagtext[i] .len) ; tpt += len; ) ιnfo->text = text; mfo->tmax = tmax; ιnfo->tpt = tpt, return(ret) , ) static int ApplyTypeStylelPara "para, int start, int end, char "inistr, char "endstr) { viawβdit.c Fri Mar 24 13:24:55 1995 29 char *pt, *tpt, *ept, *spt, 'sept, 'text, int lien, elen, len, off, tmax, nlevel, ret, char "nesting = NULL; struct bufinfo info; int tag, nmax; ilen = HTML_len(inistr) ,- elen = HTML_len(endstr) , if (( start==0 it end=-para->tlen ) || HTML_matched(para->text+start.end-start) ) { if ( para->tlen+ιlen+elen+l > para->tmax ) para->text = myrealloc(para->text,para->tmax = para->tlen+ιlen+elen+10) , for ( pt=para->text+para->tlen+l, pt>=para->text+end, —pt ) memcpyIpara->tex +end+ιlen,endstr,elen) ; for ( /*pt=para->text+end*/; pt>=para->text+start, —pt 1 ptdlen] = "pt; memcpy(para->text+start,inistr,ilen) , para->tlen += ilen+elen; ret = end + ilen; ) else { /* This is the hard case. We have to change the style on a string */ /* w th an unmatched set of html tags We do this by breaking the */ /* edit up into small bits, each of which has been forced to match */ tmax = para->tlen + 2* (llen+elen)+10, text = myalloc(tmax) ; memcpy(text,para->text,start1 ; memcpy(text+start,inistr,ilen) ; tpt = text+start+ilen; pt = para->text+start, ept = para->text+end, nlevel = 0; nmax = 0, spt = pt; while ( pt<ept ) ( if ( "pt'=HTML_MARK ) ++pt; else { tag = ((unsigned char *) pt) [HTML_POS_TAG] , if ( tag==END_TAG it nlevel==0 ) ( /* END with nothing to match it */ sept = pt; do { pt += HTML_END_LEN, /* Skip all the ends here */ ) while ( *pt=»HTML_MARK ii ((unsigned char *) pt) [HTML_POS_TAG]==END_TAG ), if ( pt-spt+ιlen+elen+(tpt-tex )>tmax ) { off = tpt-text, text = myrealloc(text,tmax = pt-spt+ιlen+elen+(tpt-text)+10) , tpt = text+off, ) memcpy(tpt,spt,sept-spt) ; memcpy(tp +=(sept-spt) ,endstr,elen) ; me cpy!tpt+=elen,sept,pt-sept) ; memcpyItpt+=(pt-sept) ,inistr,ilen) , spt = pt; tpt += ilen; ) else if ( tag==END_TAG 1 { —nlevel; len = I (unsigned char *) pt) [HTML_LEN_HIGH]"256+( (unsigned char • ) pt) |HTML_LEN_LOW] , pt += len+HTML_HEAD_LEN; ) else if ( TagNeedsTermmator(tag) ) ( if ( nlevel>=nmax ) nesting = (char **) myrealloc( (char *) nesting, (nmax+=10) "sizeof (char *) ) nesting[nlevel++] = pt; len = ((unsigned char *) pt) [HTML_LEN_HIGHJ"256+( (unsigned char *) pt) ▼iawadit.c Fri Mar 24 13:24:55 1995 30 [HTML_LEN_LOW] ; pt += len+HTML_HEAD_LEN; } else { pt += Taglncr(pt) ; ) ) ) if ( pt-spt+ (tpt-text)>tmax ) { off = tpt-text; text = myrealloc(text,tmax = pt-spt+ (tpt-text)+10) , tpt = text+off, } memcpy(tpt,spt.pt-spt) , tpt += (pt-spt) ,- info.text = text, info.tiflax = tmax, info.tpt = tpt; ret = AvoidNestmg(tinfo,nlevel,0, (unsigned char ") nesting,endstr,elen) , text = info.text, tmax = info.tmax; tpt = mfo.tpt; lf ( (tpt-text)+para->tlen-end+l >= tmax ) ( off = tpt-text, text = myrealloc(text,tmax = (tpt-text)+para->tlen-end+10) , tpt = text+off; ) memcpy(tpt,para->text+end,para--»tlen-end+l) , /* +1 gets the nul */ tpt += para->tlen-end; myfree(para->text) , para->text = text, para-> max = tmax, para->tlen = tpt-text; myfree( (char *) nesting), ) return( ret ) ; ) static int RemoveTypeStyle(Para 'para, int start, mt end, int tag,int 'endoff) { Nestinfo ni,- int l; int ιnιtιal_remove = true, char endstr[HTML_END_LEN+1] , char 'pt, *ept, 'text, *spt, int tlen, tmax, int nlevel, int ret; struct bufinfo info, FindNesting(para,start,im) , for ( ι=nι.ncnt-l; ι>=0 , —I ) f ( ni.nestin [l]==tag ) break; if ( endoff'=NULL ) "endoff = start, if ( ι==-l ) { /* Not found */ while ( para->text[star J==HTML_MARK ) { if ( tag == ((unsigned char *) para->text) [start+HTML_POS_TAG] ) break; start += ( (unsigned char *) para->text) [start+HTML_LEN_HIGH] "256+ ((unsigned char *) para->text) [start+HTML_LEN_LOW]+HTML_HEAD_LE , ) if ( para->text [start] '=HTML_MARK ) /* Couldn't find this tag here*/ return(end); /* so don't do anything */ } else { pt = (char *) ni.tagtext[ij ; while ( pt<para->text+start tt *pt==HTML_MARK ) pt += ((unsigned char *) pt) [HTML_LEN_HIGH]*256+ ((unsigned char *) pt) [HTML_LEN_LOW]+HTML_HEAD_LEN, ▼iawβdit.c Fri Mar 24 13:24:55 1995 31 if ( *pt-=HTML_MARK ) start = (char *) m. agtext[l]-para->text; else nιtial_remove = false; ) text = myalloc(tmax = para->tlen+10) ; tlen = 0; /* At this point we either want to remove the start tag that we found */ /* or put an end tag in at start (we can't always do the first if the */ /* nesting does not permit it */ memcpy(text, ara->text,start) ; tlen = start; if ( !inιtial_remove ) { info.text = text; info.tmax = tmax; info.tpt = text+start; endstr[0]=HTML_MARK; endstr[HTML_LEN_HIGH]=0; endstr[HTML_LEN_LOW]=1,• endstr[HTML_POS_TAG)= END_TAG; endstr[HTML_END_TAG]=tag; endstr[HTML_END_LENJ='\0' ret = AvoidNesting(tιnfo,nι.ncnt,i+l,m.tagtext,endstr,HTML_END_LEN) ,- text = info.text; tmax = info.tmax; tlen = info.tpt-tex ,- } else start += Taglncr(para->text+start) ; /* Yes this is safe */ pt = para->text+start; ept = para->text+end; spt = pt; while ( *ept==HTML_MARK ti ((unsigned char *) ept) [HTML_POS__TAG]== END_TAG 1 ept += HTML_END_LEN; nlevel = 1,- while ( pt<ept ) { if ( *pt==HTML_MARK ) ( if ( ((unsigned char *) pt) [HTML_POS_TAG]== tag it nlevel==0 ) { if ( pt-spt+tlen>tmax ) text = myrealloc(text, max = pt-spt+tlen+10) ; memcpy(text+tlen,spt,pt-spt) ,- tlen += (pt-spt) ; spt = (pt ♦= Taglncr(pt) ) ; /* Yes this is safe */ ++nlevel; } else if ( ((unsigned char *) p ) [HTML_POS_TAG]== tag ) { pt += Taglncr(pt) ; ++nlevel; } else if { ((unsigned char *) pt) [HTML_POS_TAG]== END_TAG it ((unsigned char *) pt) [HTML_END_TAG]== tag ) { if ( --nlevel==0 ) { if ( pt-spt+tlen>tmax ) text = myrealloc(text,tmax = pt-spt+tlen+10) ,- memcpy(text+tlen,spt,pt-spt) ; tlen *= (pt-spt) ; if ( endoff!=NULL ) 'endoff = tlen; spt = (pt += Taglncr(pt) ) ,- /* Yes this is safe */ ) else pt += Taglncr(pt); ) else pt += Taglncr(pt) ; } else ++pt; ) if ( pt-spt+tlen>tmax ) text = myrealloc(text,tmax = pt-spt+tlen+10) ; memcpy(text+tlen,spt,pt-spt) ; tlen += (pt-spt) ; ret = tlen; if ( nlevel!=0 ) { /* The tag did not end itself inside */ /* And we must do our normal fake out stuff */ ▼iβwβdit.c Fri Mar 24 13 :24 :55 1995 32 ni .ncnt = 0 , _FιndNestιn (para,end,t ) ; for ( ι=nι.ncnt-l; ι>=0 ; --1 ) if ( nι.nestιng[ι]==tag it —nlevel==0 ) break, if ( ι==-l ) { /" Not found */ IError("Nesting screwed up in RemoveTypeStyle"); myfree(text) ,- return(end) ; ) info. ext = text; info.tmax = tmax, info.tpt = text+tlen, ret = tlen; /"ret = "/AvoidNestmg(tinfo,ni.ncnt,i+l,ni.tagtext, (char *) ni.tagtext[l] , Taglncr( (char *) ni.tagtext[I] ) ), f ( endoff!=NULL 1 'endoff = ret; text = info.text; tmax = info.tmax; tlen = info.tpt-text; } if ( tlen+(para->text+para->tlen-pt)+1 >= tmax 1 text = myrealloc(text,tmax = tlen+(para->text+para->tlen-pt)+10) , memcpy(text+tlen,pt, (para->text+para->tlen-pt)+1) ; /* +1 gets the nul */ tlen += (para->text+para->tlen-pt) ; myfree(para->text) ; para->text = text; para->tmax = tmax; para->tlen = tlen; myfree! (char *) m.nesting) i; myfreel (char *) ni.tagtext); return(ret) ; } static int DoRemoveTypeStylefPage 'page, VPara 'vpara, int start, int end, int tag, int is _undo1 { char inistr[HTML_HEAD_LEN+1] ; Selection junksel; Nestinfo ni; Para "para = vpara->para; int endoff; if ( tag==A_TAG 1 { DocPart "dp; View *vs; for ( vs = page->vιews, vs'=NULL; vs=vε->nextsame 1 vε->bookmarkmenu_dιrty = true; if ( page->doc!=NULL ) if ( dp = LookupDocPart(page->doc,fsys_nametaιl (page->url) ) ) dp->out_of_date = true, } end = RemoveTypeStyle(para,start,end,tag,tendoff) ; m.nmax = 0; ni.nesting = NULL; ni.tagtext = NULL; junksel.star .para = junksel.end.para = vpara, junksel.start.offset = endoff; junksel end.offset = end; SqueezeOutNoOps(page,para,tjunksel,tni,0,ιs_undo) , end = junksel.end.offset, HTML_FιllTa (inistr,tag) , UndoAddToggleStyle(page, false, para->pnum, start, para->pnum,junksel.start.offset, inistr) ; myfree(ni.nesting) ,- myfree(n .tagtext) ,- PageSetChanged(page,true) ; retur (end) ; } void XVT_CALLC0NV1 ViewToggleStyle(View 'view, char "inistr, int ιε_undo) ( Nestinfo ni; VPara "vpara; ▼iawadit .c Fri Mar 24 13 :24 :55 1995 33 Selection sel , oldsel ; char endstr [HTML_END_LEN+1 ] ; mt tag = I (unsigned char * ) mistr ) [HTML_POS_TAG] ; mt remove_tag ; int start ; struct undo 'base = vιew->page->undoes; if ( v ew->sel.start.none ) { VιewInιtιalCheck(vιew) ,- /* Insert an initial para if none */ oldsel.start = view->care ; oldsel.end = oldsel.start,- vιew->sel.start = oldsel.start,- vιew->sel.start.none = true; ) else { oldsel = vιew->sel; if ( oldsel.start.para =-, NULL ) oldsel.start.para = vιew->first; ) ViewUndrawSel(view,tvιew->sel) ,- /* Clear the selection */ HTML_FιllEndTa (endstr,tag) , start = oldsel.start.offset; vpara = oldsel.start.para,- set ii vpara->para->text[start]==HTML_MARK it a->text+start) '=END_TAG tt >para->text + start)) >para->text + start ) ,- ra->para,start,ini) ,- if ( ni.nesting[i]==tag ) break; remove_tag = (Kni.ncnt); vpara = oldsel.start.para; sel.start.none = false; εel.start.pmapped = true; sel.start.mapped = false; sel.end. mapped = true; sel.end.mapped = false; vιew->sel.start.none = true; vιew->caret = vιew->sel.start,- /" Do the change, one paragraph at a time */ if ( tag==A_TAG ) { DocPart *dp; View *vs; for ( vs = vιew->page->vιews; vs!=NULL; vs-vs-.-nextsame ) vs->bookmar)αnenu_dιrty = true; if ( vιew->page->doc!=NULL ) if ( dp = LookupDocPart(view->page->doc,fsyε_nametaιl (view->page->url) ) ) dp->out_of_date = true; } forever { if ( vpara->subs==NULL ) { sel.start.para ■ sel.end.para = vpara; sel.start.offset = 0; sel.end.offset = vpara->para->tlen; if ( oldsel.start.para == vpara ) sel.start.offset = oldsel.start.offset, if ( oldsel.end.para == vpara ) sel.end.offset = oldsel.end.offset, SaveWhatlnfoWeNeedForRedraw(vιew->page,tsel) , if ( remove_tag ) { sel.end.offset = RemoveTypeStyle(vpara->para, sel.start.offset.sel.end.offset,tag, ULL) ,- ) else { sel.end.offset = ApplyTypeStyle(vpara->para, sel.star .offset,sel.end.offset, inistr.endstr) ; ▼iawadit.c Fri Mar 24 13 :24 : 55 1995 34 ) if ( remove_tag || 'vιew->sel.start.none ) SqueezeOutNoOps(vιew->page,vpara->para,tsel,ini, 0,ιε_undo) , ReMetrιcEverythmgChanged(vιew->page,tsel) , RedrawEverythingChanged(view->page,tsel,false) , ) if ( vpara==oldsel.end.para ) break, if ( vpara->εubs'=NULL ) vpara = vpara->subs; else { while ( vpara'=NULL tt vpara->post=»NULL ) vpara = vpara->parent; if ( vpara'=NULL ) vpara = vpara->post, ) if ( vpara==NULL ) break; } •if 0 if ( vιew->sel.start.none ) UndoAddToggleStyle(vιew->page, ιs_undo, vιew->caret.para->para->pnum, view-.-care .offset, vιew->caret.para->para->pnum,sel end.offset, inistr) ; else •endif UndoAddToggleStyleIvιew->page,ιs_undo, vιew->sel.start.para->para->pnum, vιew->sel.start.offset, oldsel.end.para->para->pnum,sel.end.offset, mistr) ; if I oldsel.start.para == oldsel.end.para tt oldsel.start.offset == oldsel end.offset ) { oldsel.start.offset = sel.end.offse , oldsel.start.mapped = false; vιew->caret = oldsel.start; ViewShowCaret(view) , ) else { /* oldsel.start needs to be adjusted if we are centering */ oldsel.end.offset = sel.end.offset, oldsel.end.mapped = false; oldsel.star .mapped = false, oldsel.start.none = ( oldsel.start.para == oldsel.end.para tt oldsel.star .offset == oldsel.end.offset ); ViewUpdateSel(view,toldsel) ; ViewShowEmphasis(view) ; ) myfree( (char *) ni.nesting); myfree( (char *) m.tagtext) ,- ViewRefreshBookmarkMenu(view) ; PageSetChanged(view->page,true) , UndoAddMultιple(vιew->page, false,base) , VιewSelectιonHasChanged(vιew) ; ) void XVT_CALLC0NV1 ViewSimpleToggleStyle(View 'view, t tag) { char buffer[HTML_HEAD_LEN+1] ; HTML_FιllTa (buffer,tag) ; ViewToggleStyle(view,buffer, false) , void XVT_CALLC0NV1 ViewPlainStyle(View 'view) { struct undo 'base = vιew->page->undoes, ▼iawβdit.c Fri Mar 24 13:24:55 1995 35 Selection oldsel, cursel, Nestinfo ni; int i; char *pt, *end; mt endoff, startoff, ptoff, hassel; VPara 'vpara; Para *para; ViewUndrawSel (view,tvιew->sel) ,- /* Clear the selection */ if ( vιew->sel.start.none ) { oldsel.start = vιew->caret; oldsel.end - vιew->caret; hassel = 0; ) else { oldsel = vιew->sel; oldsel.start.drawn = true; vιew->sel.star .none = true; vιew->caret = vιew->sel.star , hassel = true; ) if { oldsel.start.para==NULL ) { oldsel.start.para = vιew->first; if ( vιew->fιrST==NULL ) return,- } pt = oldsel.start.para->para->text + oldsel.start.offset, while ( *pt==HTML_MARK it ((unsigned char *) pt) [HTML_POS_TAG]==END_TAG ) pt += HTML_END_LEN; if ( oldsel.end.para == oldsel.start.para it pt-oldsel.end.para->para->text>oldsel.end.offset ) oldsel.end.offset = pt-oldsel.end.para->para->text; if ( !hassel ) oldsel.start.offset = oldsel.end.offset, FindNesting(oldsel.start.para->para,oldsel.start.of se ,tm) ,- for ( ι-nι.ncnt-1, ι>=0 it (char *) m.tagtext[i]+TagLen( (char *) ni.tagtex [l])==pt; —i ) pt = (char *) ni.tagtext[I] ; oldsel.start.offset = pt - oldsel.start.para->para->text,- if ( !hassel ) oldsel.end.offset = oldsel.start.offset, SaveWhatInfoWeNeedForRedraw(vιew->page,toldsel) , cursel = oldsel,- endoff = cursel.start.offset; for ( ι=nι.ncnt-l; ι>=0; —l ) { if I nι.nestιng[ι]>=STYLE_START ti ni.nesting[i]<=STYLE_END ) { endoff = DoRemoveTypeStyleIview->page,cursel.start.para, cursel.start.offset, cursel.start.para 1 =cursel.end.para' cursel.start.para->para->tlen: cursel.end.o fset, ni.nes gti] ,false) ; if ( cursel.end.para == cursel.start.para ) cursel.end.offset = endoff; } ) pt = cursel.start.para->para->text + cursel.εtart.offset; while ( *pt==HTML_MARK it ((unsigned char *) pt) [HTML_POS_TAG]==END_TAG ) pt += HTML_END_LEN; startoff = pt-cursel.start.para->para->text; ReMetricEverythingChanged(vιew->page,toldsel) ; RedrawEverythιngChanged(vιew->page,ioldsel,false) , if ( !hassel ) { vιew->caret = cursel.end; -riawadit.c Fri Mar 24 13:24:55 1995 36 ) else { vpara = cursel.star .para; do { para = vpara->para; cursel.start.para = cursel.end.para = vpara; cursel.start.offset = startoff,- cursel.end.offset = vpara!=oldsel.end.para?para->tlen: oldsel.end.para==oldsel.start.para?cursel.end.offset: oldsel.end.offset; if ( para->text !=NULL ) { SaveWha lnfoWeNeedForRedraw(view->page,icursel) ; end = para->text+cursel.end.offset; pt = para->text+startoff,- while ( pt<end it *pt!='\0' ) { if ( *pt==HTML_MARK tt HTML_tag(pt)>=STYLE_START ii HTML_tag(pt)<=STYLE_END ) { ptoff = pt-para->text; endoff = DoRemoveTypeStyle(view->page,vpara,pt-para->text, end-para->text, HTML_tag(pt) , false) ; pt = para->text+ptoff; end = para->text+endoff; ) else pt += Taglncr(pt) ; } ReMetricEverythingChanged(view->page,tcursel) ; RedrawEverythingChanged(view->page,icursel, false) ; ) if ( para==oldsel.end.para->para ) { cursel.end.offset = pt-para->text,- break; ) if ( vpara->subs!=NULL ) vpara = vpara->subs; else ( while ( vpara!=NULL tt vpara->post==NULL ) vpara = vpara->parent; if ( vpara!=NULL 1 vpara = vpara->post; ) startoff = 0; } while ( vpara!=NULL 1 ; } UndoAddMultiple(view->page,false,base) ; ViewRefreshBookmarkMenu(view) ; myfree! (char *) ni.nesting) ; myfree( (char *) ni.tagtext) ; if ( hassel ) { cursel.start = oldsel.start; cursel.start.drawn = false; cursel.start.mapped=false; cursel.start.pmapped = true; cursel.end.mapped=false; cursel.end.pmapped = true; view->sel = cursel; ViewDrawSel(view,iview->sel) ; /* Redraw the selection */ i ) void XVT_CALLCONVl ViewMakePositionSafe(View 'view. Position *pos) { char *tpt, *orig=NULL; Para 'para = pos->para->para; Nestinfo ni; t i, tsize, len; if I para->text==NULL ) /* must be safe */ vitwt it.c Fri Mar 24 13:24: 55 1995 37 return ; tpt = para->text+pos->offset; while ( *tpt==HTML_MARK ti HTML_ta (tpt)==END_TAG ) tpt += Taglncr(tpt) ; FindNesting(para,tpt-para->text,tni) ; for ( ι=nι.ncnt-l; ι>=0 ti (char *) ni.tagtext[l]+TagLen( (char *)nι.tagtext[I] )==tpt,• —i ) tpt = (char *) ni.tagtext[I] ,- ni.ncnt = i+l; pos->offset = tpt-para->text; if ( ι==-l ) return; tsize = 0; tsize += ni.tagtext[I] [HTML_LEN_HIGH] '256+ m.tagtext[l] [HTML_LEN_LOW]+HTML_HEAD_LEN+HTML_END_LEN, if ( tsιze+para->tlen+l>=para->tmax ) { orig = para->text; para->text = myalloc(para-> max += tsize ), memcpy(para->text,orig,para->tlen+l) ; ) para->tlen += tsize; for ( ι=para->tlen; ι>=pos->offset ,- —I ) para->text[i+tsize] = para->text[1] ; tpt = para->text+ι+l; for ( ι=nι.ncnt-l, ι>=0; --ι ) { tpt[0] = HTML_MARK; tpt[HTML_LEN_HIGH)=0; tpt[HTML_LEN_LOW]=1, tpt[HTML_POS_TAG]= END_TAG; tpt[HTML_END_TAG]= m.tagtext[i] [HTML_POS_TAG] ; tpt += HTML_END_LEN; } pos->o set = tpt-para->text; len = ni.tagtext[ι][HTML_LEN_HIGH] '256+ m.tagtext[l] [HTML_LEN_LOW]+HTML_HEAD_LEN; memcpy(tpt,ni.tagtext[i] .len) , tpt += len; ) myfree(ni.nesting) ; myfree(ni.tagtext) , myfree(orig) , ) void XVT_CALLC0NV1 ViewMakeSelectionSafe(View 'view. Selection *sel) { int oldtlen; lf ( εel->start.para==NULL ) return; /* Nothing there, must be safe */ oldtlen - sel->start.para->para->tlen; ViewMakePositionSafe(view,tsel->start) ; if ( sel->start.para == sel->end.para ) sel->end.offset += sel->start.para->para->tlen-oldtlen, ViewMakePositionSafe(view,tsel->end) ; ) Changing Paragraph Tags /* This and the following routine are parallel routines to muck with the */ /* parallel data structures of Paras and VParas They remove a paragraph * /* and move all the paragraphs under t up one level */ static void XVT_CALLC0NV1 Re oveVParasTa (Page "page, int pnum) { viβwadit .c Fri Mar 24 13 : 24 : 55 1995 38 VPara 'vpara , ' last , 'prev, 'next , View *vs ; for ( vs=page-> iews; vs'=NULL; vs = vs->nextsame ) { if ( (View *) xvt_vobj_get_data(vs->w)==vs ) { vpara = ViewGetVPara(vs,NULL,pnum) ; if ( vpara->parent==NULL ) prev = vs->fιrst; else prev = vpara->parent->subs, next = vpara->subs; if ( next"NULL ) next = vpara->post; if ( prev==vpara it vpara->parent==NULL ) vs->f rst = next; else if ( prev==vpara ) vpara->parent->subs = next; else { while ( prev->pos '=vpara ) prev = prev->post; prev->post = next; ) for ( last=vpara->subs; laεt'=NULL tt l st->pos '=NULL; last=last->poεt) last->parent = vpara->parent, if ( last'=NULL ) { last->post = vpara->post; last->parent = vpara->parent; ) /* This and the following routine are parallel routines to muck with the */ /* parallel data structures of Paras and VParas. They remove a paragraph */ /* and move all the paragraphs under it up one level */ static void XVT_CALLCONVl RemoveParasTag(Page 'page, Para *para) { Para 'last, 'prev, 'next; if ( para->parent==NULL 1 prev = page->fιrst, else prev = para->parent->first; next = para->first; if ( next==NULL ) next = para->post; if ( prev==para tt para->parent==NULL ) page->fιrst = next; else if ( prev==para ) para->parent->first = next; else { while ( prev->post'=para ) prev = prev->post; prev->post = next; ) for ( last=para->fιrst; last'=NULL it last->post'=NULL; last=laεt->post ) last->parent = para->parent; if ( last'=NULL ) { last->post = para->post; last->parent = para->parent; ) myfree(para) ; ) /* This and the following routine are parallel routines to muck with the */ /* parallel data structures of Paras and VParas. They insert a paragraph */ /* on top of a list of paragraphs */ ▼iawadit.c Fri Mar 24 13:24:55 1995 39 static Para * XVT_CALLCONVl InsertParasTag(Page "page, Para "first. Para "end, int tag) { Para "para, "last, "prev,- para = newPara{} ; para->tag = tag, para->pnum = -1; para->fιrst = first; if ( fιrst->parent==NULL ) prev = page->fιrst; else prev = fιrst->parent->first; if ( prev==fιrst it fιrst->parent-=NULL ) page->first = para; else if I prev==fιrst ) { fιrst->parent-> irst = para; para->parent = ιrst->parent, } else { para->parent = fιrst->parent,- while ( prev->post'=first ) prev = prev->post, prev->post = para; ) for ( laεt=fιrst; last'=NULL it last->pnum<=end->pnum; last=last->post ) { last->parent = para, prev = last; ) if ( last'=NULL ) para->post = last; prev->post = NULL; return(para) , } /* This and the previous routine are parallel routines to muck with the */ /* parallel data structures of Paras and VParas They insert a paragraph */ /* on top of a list of paragraphs */ static void XVT_CALLC0NV1 InsertVParasTag(Page 'page, VPara 'first, VPara 'end. Para 'para ) { VPara 'vpara, 'last, 'prev, View *vs,- for ( vs=page->vιews; vs'=NULL; vε = vs->nextsame ) { if ( (View *) xvt_vobj_get_data(vε->w)=-vs ) { vpara = (VPara *) myalloc(sizeof(VPara) ) ,- vpara->para = para; vpara->subs = first; vpara->y = fιrst->y; if ( fιrst->parent==NULL ) prev = vs->fιrst; else prev = fιrst->parent->subs; lf ( prev==fιrst it fιrst->parent==NULL ) vs->fιrst = vpara; else if ( prev==fιrst ) fιrst->parent->subs = vpara; else { while ( prev->post'=first ) prev = prev->post; prev->post = vpara; ) vpara->parent = fιrst->parent, for { last=fιrst; last'=NULL it last->para->pnum<=end->para->pnum, last=last-> post ) { last->parent = vpara, prev = last. ▼iawβdit.c Fri Mar 24 13 : 24 :55 1995 40 ) if ( last ! =NULL ) vpara->post = last; prev->post = NULL; ) ) ) /* For the given paragraph change its tag (ie from HI to H7 or UL to OL) */ /* Here we assume that the alteration is legal. Error checking must be done */ /* elsewhere */ void XVT_CALLCONVl ViewAlterParaTa (View 'view, VPara 'vpara, int tag, int is_undo) { Selection implied; int oldtag = vpara->para->tag; if I oldtag==tag ) return; ViewUndrawSel (view,tview->sel) ; /* Clear the selection */ ViewSelectAllUnder(view,vpara,timplied) ; SaveWha InfoWeNeedForRedra (view->page,timplied) ; vpara->para->tag = tag; ReMetricEverythingChanged(view->page,timplied) ,- RedrawEverythingChanged(view->page,timplied,true) ; UndoAddAlterTag(view->page, is_undo,vpara->para->pnum,oldtag) ,- PageSetChanged(view->page. true) ; ) void XVT_CALLC0NV1 ViewsAlterParaTag(Page 'page, Para 'para, int tag, int is_undo) { View *vs; VPara *vp; for ( vs=page->views; vsi=NULL; vs=vs->nextsame ) { if ( vs»=(View *) xvt_vobj_get_data (vs->w) ) { vp = ViewGetVPara(vs, ULL,para->pnum) , • ViewAlterParaTag Ivε,vp, tag, is_undo) ,- ) ) ) /* Remove this paragraph and move everything under it up one level in the tree*/ void XVT_CALLCONVl ViewRemoveParaTag(View 'view, VPara 'vpara, int is_undo) { int oldtag = vpara->para-> ag; Selection implied; ViewUndrawSel (view,tview->sel) ; /* Clear the selection */ ViewSelectAllUnder(view,vpara,timplied) ; SaveWhatInfOWeNeedForRedraw(view->page,timplied) ; if ( implied.start.para==vpara ) implied.start.para=vpara->subs; Re oveVParasTag(view->page,vpara->para->pnum) ; Re oveParasTag(view->page,vpara->para) ; RenumberParas (view->page) ,- ReMetricEverythingChanged(view->page,timplied) ; RedrawEverythingChanged(view->page,iimplied, true) ; UndoAddInsertTag(view->page, is_undo, implied.start.para->para->pnum, implied.end. ara->para->pnum,oldtag) ; PageSetChanged(view->page, true) ; ) void XVT_CALLCONVl ViewsRerooveParaTag(Page 'page, Para 'para, int iε_undo) { View "vs,- VPara *vp; ▼iawβdit.c Fri Mar 24 13:24:55 1995 41 for ( vs=page->vιewε; vε'=NULL; vs-vs->nextsame ) { if ( vs==(Vιew *) xvt_vobj_get_data(vs->w) ) { vp = ViewGetVPara(vs.NULL,para->pnum) ; ViewRemoveParaTag(vs,vp,ιs_undo) ; ) ) ) /* Put a paragraph on top of all paragraphs in the selection */ void XVT_CALLC0NV1 VιewInsertParaTag(Vιew 'view. Selection *sel, mt tag, int ιs_undo, int oldselnone) { Para "para; Selection implied; SaveWhatInfoWeNeedForRedraw(vιew->page,sel) ; para = InsertParasTag!view->page,sel->start.para->para,sel->end.para->para, tag) ; InsertVParasTag(view->page,sel->star .para,sel->end.para,para) , RenumberParas(vιew->page) , implied = "sel; /* Force update of th s too */ implied.star .para = sel->start,para->parent; implied.start offset = 0, while ( implied.end.para->subs'=NULL ) { implied.end.para = implied.end.para->subs; while ( implied.end.para->post'=NULL ) implied.end.para = implied.end.para->post, implied.end.offset = implied.end.para->para->tlen; ) view->sel.start.none = oldselnone; vιew->sel.start.mapped = false; vιew->sel.end.mapped = false, ReMetricEverythingChanged(vιew->page,timplied) , RedrawEverythιngChanged(vιew->page,sel,true) ,- UndoAddRemoveTag(vιew->page,ιs_undo,para->pnum) , PageSetChange (vιew->page,true) ; } void XVT_CALLCONVl VιewsInsertParaTag(Page 'page. Selection *sel, int tag, t ιs_undo) { View "vs; Selection newsel, for ( vs=page->vιews, vε'=NULL; vs=vs->nextsame ) { if ( vs==(Vιew *) xvt_vobj_get_data(vs->w) ) { newsel.start.para = ViewGetVPara(vs,NULL,sel->start.para->para->pnum) ; newsel.end.para = ViewGetVPara(vs,NULL,sel->end.para->para->pnum) , newsel.start.offset = 0; newsel.end.o set = sel->end.offset; ViewInsertParaTag(vs.tnewsel,tag,ιs_undo,vs->sel.start.none) ; ) /....••..... * ..».............. styles in Menu • * ••+«•• ** +*• * • *** ••"••• * "•»• ** void XVT_CALLC0NV1 ViewShowEmphasis(View 'view) { /* This was commented out I (GWW) don't know why Perhaps it doesn't work */ /* under windows 7 */ long mask=0; Nestlnfo ni; Position "pos; int l ,- char *pt, "end; WINDOW toolbar; static int mιd[] = { PageMenu_Bold, PageMenu_Italιc, PageMenu_Underl e, PageMenu_Fιxed, PageMenu_Address, PageMenu_Cιtatιon, PageMenu_Code, PageMenu_Defιnιtιon, PageMenu_Emphasιε, PageMenu_Keyboard, PageMenu_Sample, PageMenu_Strong, PageMenu_Sub, PageMenu_Format_Sup, ▼iawadit.c Fri Mar 24 13:24:55 1995 42 PageMenu_Variable } ,- static int tid[J= { 5,6,7,0 WInfo "winfo = view->winfo; if ( view->sel.start.none ) pos = tview->caret,- else pos = iview->sel.start; if < pos->para!=NULL } ( pt = pos->para->para->text+pos->offset; end = view->sel.start.none?pt: view->εel.star .para==view->εel.end.para?pos->para->para->text* iew->sel.e nd.offse : pos->para->para->text+pos->para->para->tlen; while ( pt<end ii *pt==HTML_MARK ti !TagHasWidth(pt) /'it ((unsigned char *) pt) [HTML_P0S_TAG] !=END_TAG*/ ) pt += Taglncr(pt); FindNesting(pos->para->para,pt-pos->para->para->text,ini) ; for ( i=0; i<ni.ncnt; ++i ) { switch ( ni.nestin [i] ) { case B_TAG: case I_TAG: case U_TAG: case TT_TAG: case ADDRESS_TAG: case CITE_TAG: case CODE_TAG: case DFN_TAG: case EM_TAG: case KBD_TAG: case SAMP_TAG: case STRONG_TAG: case SUB_TAG: case SUP_TAG: case VAR TAG: } } if ( winfo->emph_mask!-mask ) { for ( i=0; i<32; ++i ) { if ( (winfo->emph_mask Λ mask)t (l<<i) ) xvt_menu_εet_item_checked(view->w,mid(i] , (maski (l«i) ) ?true: false) ,- } toolbar = xvtcm_get_ctl_window(view->w,ToolBar) ,- for ( i=0; tid[i]!-0; ++i ) { if ( (winfo->emph___ιask Λ mask)i (l<<i) ) View_toglbutn_set_state (view, toolbar_get_ctl_windo ( toolbar , tid [ i ] ) , (maskt ( l«i ) ) ?DOWN : UP) ; ) winfo->emph_mask = mask;

Claims: We claim: 1. A method for publishing electronic documents on a wide area network ("WAN") comprising a plurality of servers, said method for use by a user having a client computer operably coupled to a first server, said method comprising the following steps: accessing a source document located on a source server, the source document including at least one hypermedia link addressing a target document located on a target server; accessing the target document by signaling the hypermedia link using a cursor control device; editing the target document; and saving the target document as modified on a destination server, wherein the foregoing steps are performed with the client computer using a seamless user interface, regardless of whether the first, source, target, and destination servers are the same or different servers. 2. The method of claim 1 wherein the step of editing the target document includes the step of copying a portion of the source document into the target document using a curser-control device. 3. The method of claim 2, wherein the copied portion of the source document includes one or more hypermedia links. 4. The method of claim 1 wherein the step of editing the target document further includes the following steps: encoding a portion of the target document with one or more display instructions using a standard mark-up language of the WAN; upon performance of the encoding step, rendering an appearance of the target document in accordance with the display instructions. 5. The method of claim 4 wherein the step of encoding includes the step of interactively selecting one or more menu commands. 6. A method for publishing electronic documents on a WAN comprising a plurality of servers, for use by a user having a client computer operably coupled to a first server, said method comprising the following steps: accessing a source document located on a source server, and a target document located on a target server; and copying a pointer addressing the target document into the source document using a cursor control device, thereby creating a hypermedia link from the source document to the target document, wherein the foregoing steps are performed with the client computer using a seamless user interface, regardless of whether the first, source, and target servers are the same or different servers. 7. The method of claim 6, wherein the step of accessing the target document further includes the following steps: selecting an anchor " item of content within the source document; automatically generating a list of one or more suggested target documents for the selected anchor item; and interactively selecting one of the suggested target documents as the target document. 8. The method of claim 7 wherein the step of selecting an anchor item of content includes the step of automatically generating a list of one or more suggested anchor items, and wherein the steps of claim 7 are performed for one or more of the suggested anchor items. 9. A method for publishing and managing a collection of related documents on a WAN, the method comprising the following steps: specifying the related documents to be included in the collection; and collectively performing a desired operation on each document in the collection, by interactively issuing a single command corresponding to the operation. 10. The method of claim 9, wherein the desired operation includes setting one or more access controls for the collection of documents. 11. The method of claim 9, wherein the desired operation includes modifying a common portion of content within the collection of documents. 12. The method of claim 9, wherein one or more source documents and target documents of the collection are linked by one or more hypermedia links, and wherein the step of collectively performing a desired operation comprises moving the collection of documents from an original location to a different location on die WAN without modifying the hypermedia links. 13. The method of claim 12, wherein one or more of the hypermedia links addresses one of the target documents relative to one of the source documents. 14. The method of claim 13, further including the step of creating one or more external hypermedia links within one or more source documents of the collection, each of said external hypermedia links absolutely addressing one more documents outside the collection. 15. The method of claim 9, further including the step of displaying on a client computer of the WAN a graphical icon corresponding to each one of the documents in the connection, and a graphical line corresponding to each one of the hypermedia links within the collection. 16. The method of claim 15, further including the step of accessing a document of the collection by using a cursor control device to signal the corresponding icon. 17. The method of claim 15, wherein the graphical icons and the graphical lines each have one or more display attributes indicating one or more states of the corresponding documents and hypermedia links. 18. A method for providing interactive application services on a WAN comprising a plurality of servers, for use with a client computer operably coupled to a first server, said method comprising the following steps: creating a template form comprising one or more informational fields and one or more hypermedia links, said links addressing one or more utility programs stored on an application server; interactively filling in the informational fields on the template form; interactively selecting one or more of the hypermedia links; and processing the template form by executing the utility programs in response to the previous step, wherein the steps of creating and filling in the template form and selecting d e hypermedia link are all performed using a seamless user interface accessed via die client computer, regardless of whether the first server and application server are the same or are different servers. 19. The method of claim 18 for use widi a database residing on said application server, wherein the one or more utility programs include one or more database management mechanisms, and wherein the step of processing the template form includes at least one or more of the following steps: inserting, retrieving, updating, and deleting one or more entries of said database. 20. The method of claim 19 for use in indexing a plurality of documents located on any one or more servers of d e WAN, wherein the step of filling in the template form comprises describing one or more of die documents. 21. The meϋiod of claim 19 for use in accounting one or more costs associated with a plurality of documents located on one or more servers of die WAN, wherein the step of filling in the template form comprises die step of specifying cost information for one or more of the documents. 22. The method of claim 19, wherein die step of creating the template form includes creating a table including a set of data specifications corresponding to the informational fields, and registering said table widi the application server. 23. T e method of claim 18, wherein the one or more hypermedia links addressing one or more utility programs each include one or more internal fields of data specifying one or more operations to be performed by die utility programs. 24. The method of claim 23, wherein die internal fields of data further specify one or more argument values for use in performing said operations. 25. The method of claim 23, wherein the internal fields of data further include one or more tags recognized by die application server. 26. The method of claim 23, further including the step of registering the operations with the application server, using the developer's client computer. 27. An apparatus for publishing electronic documents on a WAN comprising a plurality of servers, for use with a client computer operably coupled to a first server, said apparatus comprising: retrieval means for accessing a source document located on a source server, die source document including at least one hypermedia link addressing a target document located on a target server; cursor control means for accessing die target document by signaling die hypermedia link; edit means for editing the target document; and storage means for saving the target document as modified on a storage server, wherein the foregoing means are all integrated in a seamless user interface accessible via the client computer, and are operable regardless of whedier the first, source, target, and destination servers are die same or different servers. 28. An apparatus for publishing electronic documents on a WAN comprising a plurality of servers, for use with a client computer operably coupled to a first server, said apparatus comprising: source retrieval means for accessing a source document located on a source server; target retrieval means for accessing document located on a target server; and link generation means for copying a pointer addressing die target document into die source document using a cursor control device, diereby creating a hypermedia link from die source document to die target document, wherein die foregoing means are all integrated widiin a seamless user interface on the client computer, and are operable regardless of whedier die first, source, and target servers are die same or different servers. 29. An apparatus for publishing and managing a collection of related documents on a WAN, comprising: means for specifying die related documents to be included in die collection; and means for collectively performing a desired operation on each document in die collection, by interactively issuing a single command corresponding to die operation. 30. An apparatus for providing form-driven interactive services on a WAN comprising a plurality of servers, die apparatus comprising: a seamless user interface environment accessible via a client computer, said client computer operably coupled to a first server, d e seamless user interface environment further comprising: form generation means for creating a template form, said template form comprising one or more informational fields and one or more hypermedia links, said links addressing one or more utility programs stored on an application server; edit means for interactively filling in die informational fields on die template form; and cursor control means for interactively selecting one or more of the hypermedia links; and application service means, responsive to the selection of the hypermedia links, for processing the template form by executing the utility programs, wherein said apparatus is operable regardless of whedier die first server and application server are die same or different servers.

Inventors: BRADY KAREN, DAVIDSON JAMES G, DOZIER LINDA T, LONG DAVE, MCKEE DOUGLAS M, WILLIAMS GEORGE W V, BRADY, KAREN, DAVIDSON, JAMES, G., DOZIER, LINDA, T., LONG, DAVE, MCKEE, DOUGLAS, M., WILLIAMS, GEORGE, W., V.
Applicants: NAVISOFT INC, NAVISOFT, INC.
Application year: 1996
Main classification: G06F17
IPC codes: G06F12, G06F13, G06F17