]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/mac.c
4c317ed4f6718b30a2a2ff1085cdbe7fb705043f
[PuTTY.git] / mac / mac.c
1 /* $Id: mac.c,v 1.46 2003/02/07 01:33:24 ben Exp $ */
2 /*
3  * Copyright (c) 1999 Ben Harris
4  * All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following
13  * conditions:
14  * 
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 /*
28  * mac.c -- miscellaneous Mac-specific routines
29  */
30
31 #include <MacTypes.h>
32 #include <AEDataModel.h>
33 #include <AppleEvents.h>
34 #include <Quickdraw.h>
35 #include <Fonts.h>
36 #include <MacWindows.h>
37 #include <Menus.h>
38 #include <TextEdit.h>
39 #include <Appearance.h>
40 #include <CodeFragments.h>
41 #include <Dialogs.h>
42 #include <Devices.h>
43 #include <DiskInit.h>
44 #include <Gestalt.h>
45 #include <LowMem.h>
46 #include <Navigation.h>
47 #include <Resources.h>
48 #include <Script.h>
49 #include <TextCommon.h>
50 #include <ToolUtils.h>
51 #include <UnicodeConverter.h>
52
53 #include <assert.h>
54 #include <limits.h>
55 #include <stdarg.h>
56 #include <stdlib.h>             /* putty.h needs size_t */
57 #include <stdio.h>              /* for vsprintf */
58
59 #define PUTTY_DO_GLOBALS
60
61 #include "macresid.h"
62 #include "putty.h"
63 #include "ssh.h"
64 #include "mac.h"
65
66 #if TARGET_API_MAC_CARBON
67 /*
68  * This is used by (I think) CarbonStdCLib, but only exists in
69  * CarbonLib 1.1 and later.  Muppets.  Happily, it's documented to be
70  * a synonym for NULL.
71  */
72 #include <CFBase.h>
73 const CFAllocatorRef kCFAllocatorDefault = NULL;
74 #else
75 QDGlobals qd;
76 #endif
77
78 Session *sesslist;
79
80 static int cold = 1;
81 static int borednow = FALSE;
82 struct mac_gestalts mac_gestalts;
83
84 static void mac_startup(void);
85 static void mac_eventloop(void);
86 #pragma noreturn (mac_eventloop)
87 static void mac_event(EventRecord *);
88 static void mac_contentclick(WindowPtr, EventRecord *);
89 static void mac_growwindow(WindowPtr, EventRecord *);
90 static void mac_activatewindow(WindowPtr, EventRecord *);
91 static void mac_activateabout(WindowPtr, EventRecord *);
92 static void mac_updatewindow(WindowPtr);
93 static void mac_updatelicence(WindowPtr);
94 static void mac_keypress(EventRecord *);
95 static int mac_windowtype(WindowPtr);
96 static void mac_menucommand(long);
97 static void mac_openabout(void);
98 static void mac_openlicence(void);
99 static void mac_adjustcursor(RgnHandle);
100 static void mac_adjustmenus(void);
101 static void mac_closewindow(WindowPtr);
102 static void mac_zoomwindow(WindowPtr, short);
103 #pragma noreturn (cleanup_exit)
104
105 struct mac_windows {
106     WindowPtr about;
107     WindowPtr licence;
108 };
109
110 struct mac_windows windows;
111
112 int main (int argc, char **argv) {
113
114     mac_startup();
115     mac_eventloop();
116 }
117
118 #pragma noreturn (main)
119
120 static void mac_startup(void) {
121     Handle menuBar;
122     TECInfoHandle ti;
123
124 #if !TARGET_API_MAC_CARBON
125     /* Init Memory Manager */
126     MaxApplZone();
127     /* Init QuickDraw */
128     InitGraf(&qd.thePort);
129     /* Init Font Manager */
130     InitFonts();
131     /* Init Window Manager */
132     InitWindows();
133     /* Init Menu Manager */
134     InitMenus();
135     /* Init TextEdit */
136     TEInit();
137     /* Init Dialog Manager */
138     InitDialogs(NULL);
139 #endif
140     cold = 0;
141     
142     /* Get base system version (only used if there's no better selector) */
143     if (Gestalt(gestaltSystemVersion, &mac_gestalts.sysvers) != noErr ||
144         (mac_gestalts.sysvers &= 0xffff) < 0x700)
145         fatalbox("PuTTY requires System 7 or newer");
146     /* Find out if we've got Color Quickdraw */
147     if (Gestalt(gestaltQuickdrawVersion, &mac_gestalts.qdvers) != noErr)
148         mac_gestalts.qdvers = gestaltOriginalQD;
149     /* ... and the Appearance Manager? */
150     if (Gestalt(gestaltAppearanceVersion, &mac_gestalts.apprvers) != noErr)
151         if (Gestalt(gestaltAppearanceAttr, NULL) == noErr)
152             mac_gestalts.apprvers = 0x0100;
153         else
154             mac_gestalts.apprvers = 0;
155 #if TARGET_RT_MAC_CFM
156     /* Paranoia: Did we manage to pull in AppearanceLib? */
157     if (&RegisterAppearanceClient == kUnresolvedCFragSymbolAddress)
158         mac_gestalts.apprvers = 0;
159 #endif
160 #if TARGET_CPU_68K
161     mac_gestalts.cntlattr = 0;
162     mac_gestalts.windattr = 0;
163 #else
164     /* Mac OS 8.5 Control Manager (proportional scrollbars)? */
165     if (Gestalt(gestaltControlMgrAttr, &mac_gestalts.cntlattr) != noErr ||
166         &SetControlViewSize == kUnresolvedCFragSymbolAddress)
167         mac_gestalts.cntlattr = 0;
168     /* Mac OS 8.5 Window Manager? */
169     if (Gestalt(gestaltWindowMgrAttr, &mac_gestalts.windattr) != noErr ||
170         &SetWindowContentColor == kUnresolvedCFragSymbolAddress)
171         mac_gestalts.windattr = 0;
172 #endif
173     /* Text Encoding Conversion Manager? */
174     if (
175 #if TARGET_RT_MAC_CFM
176         &TECGetInfo == kUnresolvedCFragSymbolAddress ||
177 #else
178         InitializeUnicodeConverter(NULL) != noErr ||
179 #endif
180         TECGetInfo(&ti) != noErr)
181         mac_gestalts.encvvers = 0;
182     else {
183         mac_gestalts.encvvers = (*ti)->tecVersion;
184         mac_gestalts.uncvattr = (*ti)->tecUnicodeConverterFeatures;
185         DisposeHandle((Handle)ti);
186     }
187     /* Navigation Services? */
188     if (NavServicesAvailable())
189         mac_gestalts.navsvers = NavLibraryVersion();
190     else
191         mac_gestalts.navsvers = 0;
192
193     sk_init();
194
195     /* We've been tested with the Appearance Manager */
196     if (mac_gestalts.apprvers != 0)
197         RegisterAppearanceClient();
198
199     menuBar = GetNewMBar(128);
200     if (menuBar == NULL)
201         fatalbox("Unable to create menu bar.");
202     SetMenuBar(menuBar);
203     AppendResMenu(GetMenuHandle(mApple), 'DRVR');
204     mac_adjustmenus();
205     DrawMenuBar();
206     InitCursor();
207     windows.about = NULL;
208     windows.licence = NULL;
209
210     default_protocol = be_default_protocol;
211     /* Find the appropriate default port. */
212     {
213         int i;
214         default_port = 0; /* illegal */
215         for (i = 0; backends[i].backend != NULL; i++)
216             if (backends[i].protocol == default_protocol) {
217                 default_port = backends[i].backend->default_port;
218                 break;
219             }
220     }
221     flags = FLAG_INTERACTIVE;
222
223 #if !TARGET_API_MAC_CARBON
224     {
225         short vol;
226         long dirid;
227
228         /* Set the default directory for loading and saving settings. */
229         /* XXX Should we create it? */
230         if (get_session_dir(FALSE, &vol, &dirid) == noErr) {
231             LMSetSFSaveDisk(-vol);
232             LMSetCurDirStore(dirid);
233         }
234     }
235 #endif
236
237     /* Install Apple Event handlers. */
238     AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
239                           NewAEEventHandlerUPP(&mac_aevt_oapp), 0, FALSE);
240     AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
241                           NewAEEventHandlerUPP(&mac_aevt_odoc), 0, FALSE);
242     AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,
243                           NewAEEventHandlerUPP(&mac_aevt_pdoc), 0, FALSE);
244     AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
245                           NewAEEventHandlerUPP(&mac_aevt_quit), 0, FALSE);
246 }
247
248 static void mac_eventloop(void) {
249     Boolean gotevent;
250     EventRecord event;
251     RgnHandle cursrgn;
252
253     cursrgn = NewRgn();
254     for (;;) {
255         mac_adjustcursor(cursrgn);
256         gotevent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursrgn);
257         mac_adjustcursor(cursrgn);
258         if (gotevent)
259             mac_event(&event);
260         if (borednow)
261             cleanup_exit(0);
262         sk_poll();
263         mac_pollterm();
264     }
265     DisposeRgn(cursrgn);
266 }
267
268 static void mac_event(EventRecord *event) {
269     short part;
270     WindowPtr window;
271
272     switch (event->what) {
273       case mouseDown:
274         part = FindWindow(event->where, &window);
275         switch (part) {
276           case inMenuBar:
277             mac_adjustmenus();
278             mac_menucommand(MenuSelect(event->where));
279             break;
280 #if !TARGET_API_MAC_CARBON
281           case inSysWindow:
282             SystemClick(event, window);
283             break;
284 #endif
285           case inContent:
286             if (window != FrontWindow())
287                 /* XXX: check for movable modal dboxes? */
288                 SelectWindow(window);
289             else
290                 mac_contentclick(window, event);
291             break;
292           case inGoAway:
293             if (TrackGoAway(window, event->where))
294                 mac_closewindow(window);
295             break;
296           case inDrag:
297             /* XXX: moveable modal check? */
298 #if TARGET_API_MAC_CARBON
299             {
300                 BitMap screenBits;
301
302                 GetQDGlobalsScreenBits(&screenBits);
303                 DragWindow(window, event->where, &screenBits.bounds);
304             }
305 #else
306             DragWindow(window, event->where, &qd.screenBits.bounds);
307 #endif
308             break;
309           case inGrow:
310             mac_growwindow(window, event);
311             break;
312           case inZoomIn:
313           case inZoomOut:
314             if (TrackBox(window, event->where, part))
315                 mac_zoomwindow(window, part);
316             break;
317         }
318         break;
319       case keyDown:
320       case autoKey:
321         mac_keypress(event);
322         break;
323       case activateEvt:
324         mac_activatewindow((WindowPtr)event->message, event);
325         break;
326       case updateEvt:
327         mac_updatewindow((WindowPtr)event->message);
328         break;
329 #if !TARGET_API_MAC_CARBON
330       case diskEvt:
331         if (HiWord(event->message) != noErr) {
332             Point pt;
333
334             SetPt(&pt, 120, 120);
335             DIBadMount(pt, event->message);
336         }
337         break;
338 #endif
339       case kHighLevelEvent:
340         AEProcessAppleEvent(event); /* errors? */
341         break;
342     }
343 }
344
345 static void mac_contentclick(WindowPtr window, EventRecord *event) {
346     short item;
347     DialogRef dialog;
348
349     switch (mac_windowtype(window)) {
350       case wTerminal:
351         mac_clickterm(window, event);
352         break;
353       case wAbout:
354         dialog = GetDialogFromWindow(window);
355         if (DialogSelect(event, &dialog, &item))
356             switch (item) {
357               case wiAboutLicence:
358                 mac_openlicence();
359                 break;
360             }
361         break;
362       case wSettings:
363         mac_clickdlg(window, event);
364         break;
365     }
366 }
367
368 static void mac_growwindow(WindowPtr window, EventRecord *event) {
369
370     switch (mac_windowtype(window)) {
371       case wTerminal:
372         mac_growterm(window, event);
373     }
374 }
375
376 static void mac_activatewindow(WindowPtr window, EventRecord *event) {
377     int active;
378
379     active = (event->modifiers & activeFlag) != 0;
380     mac_adjustmenus();
381     switch (mac_windowtype(window)) {
382       case wTerminal:
383         mac_activateterm(window, active);
384         break;
385       case wSettings:
386         mac_activatedlg(window, event);
387         break;
388       case wAbout:
389         mac_activateabout(window, event);
390         break;
391     }
392 }
393
394 static void mac_activateabout(WindowPtr window, EventRecord *event) {
395     DialogRef dialog;
396     DialogItemType itemtype;
397     Handle itemhandle;
398     short item;
399     Rect itemrect;
400     int active;
401
402     dialog = GetDialogFromWindow(window);
403     active = (event->modifiers & activeFlag) != 0;
404     GetDialogItem(dialog, wiAboutLicence, &itemtype, &itemhandle, &itemrect);
405     HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
406     DialogSelect(event, &dialog, &item);
407 }
408
409 static void mac_updatewindow(WindowPtr window)
410 {
411 #if TARGET_API_MAC_CARBON
412     RgnHandle rgn;
413 #endif
414
415     switch (mac_windowtype(window)) {
416       case wTerminal:
417         mac_updateterm(window);
418         break;
419       case wAbout:
420       case wSettings:
421         BeginUpdate(window);
422 #if TARGET_API_MAC_CARBON
423         rgn = NewRgn();
424         GetPortVisibleRegion(GetWindowPort(window), rgn);
425         UpdateDialog(GetDialogFromWindow(window), rgn);
426         DisposeRgn(rgn);
427 #else
428         UpdateDialog(window, window->visRgn);
429 #endif
430         EndUpdate(window);
431         break;
432       case wLicence:
433         mac_updatelicence(window);
434         break;
435     }
436 }
437
438 static void mac_updatelicence(WindowPtr window)
439 {
440     Handle h;
441     int len;
442     long fondsize;
443     Rect textrect;
444
445     SetPort((GrafPtr)GetWindowPort(window));
446     BeginUpdate(window);
447     fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize);
448     TextFont(HiWord(fondsize));
449     TextSize(LoWord(fondsize));
450     h = Get1Resource('TEXT', wLicence);
451     len = GetResourceSizeOnDisk(h);
452 #if TARGET_API_MAC_CARBON
453     GetPortBounds(GetWindowPort(window), &textrect);
454 #else
455     textrect = window->portRect;
456 #endif
457     if (h != NULL) {
458         HLock(h);
459         TETextBox(*h, len, &textrect, teFlushDefault);
460         HUnlock(h);
461     }
462     EndUpdate(window);
463 }
464
465 /*
466  * Work out what kind of window we're dealing with.
467  */
468 static int mac_windowtype(WindowPtr window)
469 {
470
471 #if !TARGET_API_MAC_CARBON
472     if (GetWindowKind(window) < 0)
473         return wDA;
474 #endif
475     return ((WinInfo *)GetWRefCon(window))->wtype;
476 }
477
478 /*
479  * Handle a key press
480  */
481 static void mac_keypress(EventRecord *event) {
482     WindowPtr window;
483
484     window = FrontWindow();
485     /*
486      * Check for a command-key combination, but ignore it if it counts
487      * as a meta-key combination and we're in a terminal window.
488      */
489     if (event->what == keyDown && (event->modifiers & cmdKey) /*&&
490         !((event->modifiers & cfg.meta_modifiers) == cfg.meta_modifiers &&
491             mac_windowtype(window) == wTerminal)*/) {
492         mac_adjustmenus();
493         mac_menucommand(MenuKey(event->message & charCodeMask));
494     } else {
495         switch (mac_windowtype(window)) {
496           case wTerminal:
497             mac_keyterm(window, event);
498             break;
499         }
500     }       
501 }
502
503 static void mac_menucommand(long result) {
504     short menu, item;
505     WindowPtr window;
506 #if !TARGET_API_MAC_CARBON
507     Str255 da;
508 #endif
509
510     menu = HiWord(result);
511     item = LoWord(result);
512     window = FrontWindow();
513     /* Things which do the same whatever window we're in. */
514     switch (menu) {
515       case mApple:
516         switch (item) {
517           case iAbout:
518             mac_openabout();
519             goto done;
520 #if !TARGET_API_MAC_CARBON
521           default:
522             GetMenuItemText(GetMenuHandle(mApple), item, da);
523             OpenDeskAcc(da);
524             goto done;
525 #endif
526         }
527         break;
528       case mFile:
529         switch (item) {
530           case iNew:
531             mac_newsession();
532             goto done;
533           case iOpen:
534             mac_opensession();
535             goto done;
536           case iClose:
537             mac_closewindow(window);
538             goto done;
539           case iSave:
540             mac_savesession();
541             goto done;
542           case iSaveAs:
543             mac_savesessionas();
544             goto done;
545           case iDuplicate:
546             mac_dupsession();
547             goto done;
548           case iQuit:
549             cleanup_exit(0);
550             goto done;
551         }
552         break;
553     }
554     /* If we get here, handling is up to window-specific code. */
555     switch (mac_windowtype(window)) {
556       case wTerminal:
557         mac_menuterm(window, menu, item);
558         break;
559     }
560   done:
561     HiliteMenu(0);
562 }
563
564 static void mac_openabout(void) {
565     DialogItemType itemtype;
566     Handle item;
567     VersRecHndl vers;
568     Rect box;
569     StringPtr longvers;
570     WinInfo *wi;
571
572     if (windows.about)
573         SelectWindow(windows.about);
574     else {
575         windows.about =
576             GetDialogWindow(GetNewDialog(wAbout, NULL, (WindowPtr)-1));
577         wi = smalloc(sizeof(*wi));
578         wi->s = NULL;
579         wi->wtype = wAbout;
580         SetWRefCon(windows.about, (long)wi);
581         vers = (VersRecHndl)Get1Resource('vers', 1);
582         if (vers != NULL && *vers != NULL) {
583             longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
584             GetDialogItem(GetDialogFromWindow(windows.about), wiAboutVersion,
585                           &itemtype, &item, &box);
586             assert(itemtype & kStaticTextDialogItem);
587             SetDialogItemText(item, longvers);
588         }
589         ShowWindow(windows.about);
590     }
591 }
592
593 static void mac_openlicence(void) {
594     WinInfo *wi;
595
596     if (windows.licence)
597         SelectWindow(windows.licence);
598     else {
599         windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
600         wi = smalloc(sizeof(*wi));
601         wi->s = NULL;
602         wi->wtype = wLicence;
603         SetWRefCon(windows.licence, (long)wi);
604         ShowWindow(windows.licence);
605     }
606 }
607
608 static void mac_closewindow(WindowPtr window) {
609
610     switch (mac_windowtype(window)) {
611 #if !TARGET_API_MAC_CARBON
612       case wDA:
613         CloseDeskAcc(GetWindowKind(window));
614         break;
615 #endif
616       case wTerminal:
617         mac_closeterm(window);
618         break;
619       case wAbout:
620         windows.about = NULL;
621         DisposeDialog(GetDialogFromWindow(window));
622         break;
623       case wLicence:
624         windows.licence = NULL;
625         DisposeWindow(window);
626         break;
627     }
628 }
629
630 static void mac_zoomwindow(WindowPtr window, short part) {
631
632     /* FIXME: do something */
633 }
634
635 /*
636  * Make the menus look right before the user gets to see them.
637  */
638 #if TARGET_API_MAC_CARBON
639 #define EnableItem EnableMenuItem
640 #define DisableItem DisableMenuItem
641 #endif
642 static void mac_adjustmenus(void) {
643     WindowPtr window;
644     MenuHandle menu;
645
646     window = FrontWindow();
647     menu = GetMenuHandle(mApple);
648     EnableItem(menu, 0);
649     EnableItem(menu, iAbout);
650
651     menu = GetMenuHandle(mFile);
652     EnableItem(menu, 0);
653     EnableItem(menu, iNew);
654     if (window != NULL)
655         EnableItem(menu, iClose);
656     else
657         DisableItem(menu, iClose);
658     EnableItem(menu, iQuit);
659
660     switch (mac_windowtype(window)) {
661       case wSettings:
662         DisableItem(menu, iSave); /* XXX enable if modified */
663         EnableItem(menu, iSaveAs);
664         EnableItem(menu, iDuplicate);
665         menu = GetMenuHandle(mEdit);
666         DisableItem(menu, 0);
667         break;
668       case wTerminal:
669         mac_adjusttermmenus(window);
670         break;
671       default:
672         DisableItem(menu, iSave);
673         DisableItem(menu, iSaveAs);
674         DisableItem(menu, iDuplicate);
675         menu = GetMenuHandle(mEdit);
676         DisableItem(menu, 0);
677         break;
678     }
679     DrawMenuBar();
680 }
681
682 /*
683  * Make sure the right cursor's being displayed.
684  */
685 static void mac_adjustcursor(RgnHandle cursrgn) {
686     Point mouse;
687     WindowPtr window, front;
688     short part;
689 #if TARGET_API_MAC_CARBON
690     Cursor arrow;
691     RgnHandle visrgn;
692 #endif
693
694     GetMouse(&mouse);
695     LocalToGlobal(&mouse);
696     part = FindWindow(mouse, &window);
697     front = FrontWindow();
698     if (part != inContent || window == NULL || window != front) {
699         /* Cursor isn't in the front window, so switch to arrow */
700 #if TARGET_API_MAC_CARBON
701         GetQDGlobalsArrow(&arrow);
702         SetCursor(&arrow);
703 #else
704         SetCursor(&qd.arrow);
705 #endif
706         SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
707         if (front != NULL) {
708 #if TARGET_API_MAC_CARBON
709             visrgn = NewRgn();
710             GetPortVisibleRegion(GetWindowPort(front), visrgn);
711             DiffRgn(cursrgn, visrgn, cursrgn);
712             DisposeRgn(visrgn);
713 #else
714             DiffRgn(cursrgn, front->visRgn, cursrgn);
715 #endif
716         }
717     } else {
718         switch (mac_windowtype(window)) {
719           case wTerminal:
720             mac_adjusttermcursor(window, mouse, cursrgn);
721             break;
722           default:
723 #if TARGET_API_MAC_CARBON
724             GetQDGlobalsArrow(&arrow);
725             SetCursor(&arrow);
726             GetPortVisibleRegion(GetWindowPort(window), cursrgn);
727 #else
728             SetCursor(&qd.arrow);
729             CopyRgn(window->visRgn, cursrgn);
730 #endif
731             break;
732         }
733     }
734 }
735
736 pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
737                                   long refcon)
738 {
739     DescType type;
740     Size size;
741
742     if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
743                           &type, NULL, 0, &size) == noErr)
744         return errAEParamMissed;
745
746     borednow = 1;
747     return noErr;
748 }
749
750 void cleanup_exit(int status)
751 {
752
753 #if !TARGET_RT_MAC_CFM
754     if (mac_gestalts.encvvers != 0)
755         TerminateUnicodeConverter();
756 #endif
757     sk_cleanup();
758     exit(status);
759 }
760
761 void fatalbox(char *fmt, ...) {
762     va_list ap;
763     Str255 stuff;
764     
765     va_start(ap, fmt);
766     /* We'd like stuff to be a Pascal string */
767     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
768     va_end(ap);
769     ParamText(stuff, NULL, NULL, NULL);
770     StopAlert(128, NULL);
771     cleanup_exit(1);
772 }
773
774 void modalfatalbox(char *fmt, ...) {
775     va_list ap;
776     Str255 stuff;
777     
778     va_start(ap, fmt);
779     /* We'd like stuff to be a Pascal string */
780     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
781     va_end(ap);
782     ParamText(stuff, NULL, NULL, NULL);
783     StopAlert(128, NULL);
784     cleanup_exit(1);
785 }
786
787 /* This should only kill the current session, not the whole application. */
788 void connection_fatal(void *fontend, char *fmt, ...) {
789     va_list ap;
790     Str255 stuff;
791     
792     va_start(ap, fmt);
793     /* We'd like stuff to be a Pascal string */
794     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
795     va_end(ap);
796     ParamText(stuff, NULL, NULL, NULL);
797     StopAlert(128, NULL);
798     cleanup_exit(1);
799 }
800
801 /* Null SSH agent client -- never finds an agent. */
802
803 int agent_exists(void)
804 {
805
806     return FALSE;
807 }
808
809 void agent_query(void *in, int inlen, void **out, int *outlen)
810 {
811
812     *out = NULL;
813     *outlen = 0;
814 }
815
816 /* Temporary null routines for testing. */
817
818 void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
819                          char *keystr, char *fingerprint)
820 {
821
822 }
823
824 void askcipher(void *frontend, char *ciphername, int cs)
825 {
826
827 }
828
829 void old_keyfile_warning(void)
830 {
831
832 }
833
834 FontSpec platform_default_fontspec(char const *name)
835 {
836     FontSpec ret;
837     long smfs;
838
839     if (!strcmp(name, "Font")) {
840         smfs = GetScriptVariable(smSystemScript, smScriptMonoFondSize);
841         if (smfs == 0)
842             smfs = GetScriptVariable(smRoman, smScriptMonoFondSize);
843         if (smfs != 0) {
844             GetFontName(HiWord(smfs), ret.name);
845             if (ret.name[0] == 0)
846                 memcpy(ret.name, "\pMonaco", 7);
847             ret.size = LoWord(smfs);
848         } else {
849             memcpy(ret.name, "\pMonaco", 7);
850             ret.size = 9;
851         }
852         ret.face = 0;
853     } else {
854         ret.name[0] = 0;
855     }
856
857     return ret;
858 }
859
860 Filename platform_default_filename(const char *name)
861 {
862     Filename ret;
863     if (!strcmp(name, "LogFileName"))
864         FSMakeFSSpec(0, 0, "\pputty.log", &ret.fss);
865     else
866         memset(&ret, 0, sizeof(ret));
867     return ret;
868 }
869
870 char *platform_default_s(char const *name)
871 {
872     return NULL;
873 }
874
875 int platform_default_i(char const *name, int def)
876 {
877
878     /* Non-raw cut and paste of line-drawing chars works badly on the
879      * current Unix stub implementation of the Unicode functions.
880      * So I'm going to temporarily set the default to raw mode so
881      * that the failure mode isn't quite so drastically horrid.
882      * When Unicode comes in, this can all be put right. */
883     if (!strcmp(name, "RawCNP"))
884         return 1;
885     return def;
886 }
887
888 void platform_get_x11_auth(char *display, int *proto,
889                            unsigned char *data, int *datalen)
890 {
891     /* SGT: I have no idea whether Mac X servers need anything here. */
892 }
893
894 Filename filename_from_str(const char *str)
895 {
896     Filename ret;
897     Str255 tmp;
898
899     /* XXX This fails for filenames over 255 characters long. */
900     c2pstrcpy(tmp, str);
901     FSMakeFSSpec(0, 0, tmp, &ret.fss);
902     return ret;
903 }
904
905 /*
906  * Convert a filename to a string for display purposes.
907  * See pp 2-44--2-46 of IM:Files
908  *
909  * XXX static storage considered harmful
910  */
911 const char *filename_to_str(const Filename *fn)
912 {
913     CInfoPBRec pb;
914     Str255 dirname;
915     OSErr err;
916     static char *path = NULL;
917     char *newpath;
918
919     if (path != NULL) sfree(path);
920     path = smalloc(fn->fss.name[0]);
921     p2cstrcpy(path, fn->fss.name);
922     pb.dirInfo.ioNamePtr = dirname;
923     pb.dirInfo.ioVRefNum = fn->fss.vRefNum;
924     pb.dirInfo.ioDrParID = fn->fss.parID;
925     pb.dirInfo.ioFDirIndex = -1;
926     do {
927         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
928         err = PBGetCatInfoSync(&pb);
929
930         /* XXX Assume not A/UX */
931         newpath = smalloc(strlen(path) + dirname[0] + 2);
932         p2cstrcpy(newpath, dirname);
933         strcat(newpath, ":");
934         strcat(newpath, path);
935         sfree(path);
936         path = newpath;
937     } while (pb.dirInfo.ioDrDirID != fsRtDirID);
938     return path;
939 }
940
941 int filename_equal(Filename f1, Filename f2)
942 {
943
944     return f1.fss.vRefNum == f2.fss.vRefNum &&
945         f1.fss.parID == f2.fss.parID &&
946         f1.fss.name[0] == f2.fss.name[0] &&
947         memcmp(f1.fss.name + 1, f2.fss.name + 1, f1.fss.name[0]) == 0;
948 }
949
950 int filename_is_null(Filename fn)
951 {
952
953     return fn.fss.vRefNum == 0 && fn.fss.parID == 0 && fn.fss.name[0] == 0;
954 }
955
956 FILE *f_open(Filename fn, char const *mode)
957 {
958     short savevol;
959     long savedir;
960     char tmp[256];
961     FILE *ret;
962
963     HGetVol(NULL, &savevol, &savedir);
964     if (HSetVol(NULL, fn.fss.vRefNum, fn.fss.parID) == noErr) {
965         p2cstrcpy(tmp, fn.fss.name);
966         ret = fopen(tmp, mode);
967     } else
968         ret = NULL;
969     HSetVol(NULL, savevol, savedir);
970     return ret;
971 }
972
973 /*
974  * Local Variables:
975  * c-file-style: "simon"
976  * End:
977  */