]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - mac/mac.c
c11566d03ec92c32b4405e3b692cee8f8e4bd56a
[PuTTY.git] / mac / mac.c
1 /* $Id: mac.c,v 1.47 2003/02/07 01:38:12 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       case wEventLog:
366         mac_clickeventlog(window, event);
367         break;
368     }
369 }
370
371 static void mac_growwindow(WindowPtr window, EventRecord *event) {
372
373     switch (mac_windowtype(window)) {
374       case wTerminal:
375         mac_growterm(window, event);
376         break;
377       case wEventLog:
378         mac_groweventlog(window, event);
379         break;
380     }
381 }
382
383 static void mac_activatewindow(WindowPtr window, EventRecord *event) {
384     int active;
385
386     active = (event->modifiers & activeFlag) != 0;
387     mac_adjustmenus();
388     switch (mac_windowtype(window)) {
389       case wTerminal:
390         mac_activateterm(window, active);
391         break;
392       case wSettings:
393         mac_activatedlg(window, event);
394         break;
395       case wAbout:
396         mac_activateabout(window, event);
397         break;
398       case wEventLog:
399         mac_activateeventlog(window, event);
400         break;
401     }
402 }
403
404 static void mac_activateabout(WindowPtr window, EventRecord *event) {
405     DialogRef dialog;
406     DialogItemType itemtype;
407     Handle itemhandle;
408     short item;
409     Rect itemrect;
410     int active;
411
412     dialog = GetDialogFromWindow(window);
413     active = (event->modifiers & activeFlag) != 0;
414     GetDialogItem(dialog, wiAboutLicence, &itemtype, &itemhandle, &itemrect);
415     HiliteControl((ControlHandle)itemhandle, active ? 0 : 255);
416     DialogSelect(event, &dialog, &item);
417 }
418
419 static void mac_updatewindow(WindowPtr window)
420 {
421 #if TARGET_API_MAC_CARBON
422     RgnHandle rgn;
423 #endif
424
425     switch (mac_windowtype(window)) {
426       case wTerminal:
427         mac_updateterm(window);
428         break;
429       case wAbout:
430       case wSettings:
431         BeginUpdate(window);
432 #if TARGET_API_MAC_CARBON
433         rgn = NewRgn();
434         GetPortVisibleRegion(GetWindowPort(window), rgn);
435         UpdateDialog(GetDialogFromWindow(window), rgn);
436         DisposeRgn(rgn);
437 #else
438         UpdateDialog(window, window->visRgn);
439 #endif
440         EndUpdate(window);
441         break;
442       case wLicence:
443         mac_updatelicence(window);
444         break;
445       case wEventLog:
446         mac_updateeventlog(window);
447         break;
448     }
449 }
450
451 static void mac_updatelicence(WindowPtr window)
452 {
453     Handle h;
454     int len;
455     long fondsize;
456     Rect textrect;
457
458     SetPort((GrafPtr)GetWindowPort(window));
459     BeginUpdate(window);
460     fondsize = GetScriptVariable(smRoman, smScriptSmallFondSize);
461     TextFont(HiWord(fondsize));
462     TextSize(LoWord(fondsize));
463     h = Get1Resource('TEXT', wLicence);
464     len = GetResourceSizeOnDisk(h);
465 #if TARGET_API_MAC_CARBON
466     GetPortBounds(GetWindowPort(window), &textrect);
467 #else
468     textrect = window->portRect;
469 #endif
470     if (h != NULL) {
471         HLock(h);
472         TETextBox(*h, len, &textrect, teFlushDefault);
473         HUnlock(h);
474     }
475     EndUpdate(window);
476 }
477
478 /*
479  * Work out what kind of window we're dealing with.
480  */
481 static int mac_windowtype(WindowPtr window)
482 {
483
484 #if !TARGET_API_MAC_CARBON
485     if (GetWindowKind(window) < 0)
486         return wDA;
487 #endif
488     return ((WinInfo *)GetWRefCon(window))->wtype;
489 }
490
491 /*
492  * Handle a key press
493  */
494 static void mac_keypress(EventRecord *event) {
495     WindowPtr window;
496
497     window = FrontWindow();
498     /*
499      * Check for a command-key combination, but ignore it if it counts
500      * as a meta-key combination and we're in a terminal window.
501      */
502     if (event->what == keyDown && (event->modifiers & cmdKey) /*&&
503         !((event->modifiers & cfg.meta_modifiers) == cfg.meta_modifiers &&
504             mac_windowtype(window) == wTerminal)*/) {
505         mac_adjustmenus();
506         mac_menucommand(MenuKey(event->message & charCodeMask));
507     } else {
508         switch (mac_windowtype(window)) {
509           case wTerminal:
510             mac_keyterm(window, event);
511             break;
512         }
513     }       
514 }
515
516 static void mac_menucommand(long result) {
517     short menu, item;
518     WindowPtr window;
519 #if !TARGET_API_MAC_CARBON
520     Str255 da;
521 #endif
522
523     menu = HiWord(result);
524     item = LoWord(result);
525     window = FrontWindow();
526     /* Things which do the same whatever window we're in. */
527     switch (menu) {
528       case mApple:
529         switch (item) {
530           case iAbout:
531             mac_openabout();
532             goto done;
533 #if !TARGET_API_MAC_CARBON
534           default:
535             GetMenuItemText(GetMenuHandle(mApple), item, da);
536             OpenDeskAcc(da);
537             goto done;
538 #endif
539         }
540         break;
541       case mFile:
542         switch (item) {
543           case iNew:
544             mac_newsession();
545             goto done;
546           case iOpen:
547             mac_opensession();
548             goto done;
549           case iClose:
550             mac_closewindow(window);
551             goto done;
552           case iSave:
553             mac_savesession();
554             goto done;
555           case iSaveAs:
556             mac_savesessionas();
557             goto done;
558           case iDuplicate:
559             mac_dupsession();
560             goto done;
561           case iQuit:
562             cleanup_exit(0);
563             goto done;
564         }
565         break;
566     }
567     /* If we get here, handling is up to window-specific code. */
568     switch (mac_windowtype(window)) {
569       case wTerminal:
570         mac_menuterm(window, menu, item);
571         break;
572     }
573   done:
574     HiliteMenu(0);
575 }
576
577 static void mac_openabout(void) {
578     DialogItemType itemtype;
579     Handle item;
580     VersRecHndl vers;
581     Rect box;
582     StringPtr longvers;
583     WinInfo *wi;
584
585     if (windows.about)
586         SelectWindow(windows.about);
587     else {
588         windows.about =
589             GetDialogWindow(GetNewDialog(wAbout, NULL, (WindowPtr)-1));
590         wi = smalloc(sizeof(*wi));
591         wi->s = NULL;
592         wi->wtype = wAbout;
593         SetWRefCon(windows.about, (long)wi);
594         vers = (VersRecHndl)Get1Resource('vers', 1);
595         if (vers != NULL && *vers != NULL) {
596             longvers = (*vers)->shortVersion + (*vers)->shortVersion[0] + 1;
597             GetDialogItem(GetDialogFromWindow(windows.about), wiAboutVersion,
598                           &itemtype, &item, &box);
599             assert(itemtype & kStaticTextDialogItem);
600             SetDialogItemText(item, longvers);
601         }
602         ShowWindow(windows.about);
603     }
604 }
605
606 static void mac_openlicence(void) {
607     WinInfo *wi;
608
609     if (windows.licence)
610         SelectWindow(windows.licence);
611     else {
612         windows.licence = GetNewWindow(wLicence, NULL, (WindowPtr)-1);
613         wi = smalloc(sizeof(*wi));
614         wi->s = NULL;
615         wi->wtype = wLicence;
616         SetWRefCon(windows.licence, (long)wi);
617         ShowWindow(windows.licence);
618     }
619 }
620
621 static void mac_closewindow(WindowPtr window) {
622
623     switch (mac_windowtype(window)) {
624 #if !TARGET_API_MAC_CARBON
625       case wDA:
626         CloseDeskAcc(GetWindowKind(window));
627         break;
628 #endif
629       case wTerminal:
630         mac_closeterm(window);
631         break;
632       case wAbout:
633         windows.about = NULL;
634         DisposeDialog(GetDialogFromWindow(window));
635         break;
636       case wLicence:
637         windows.licence = NULL;
638         DisposeWindow(window);
639         break;
640     }
641 }
642
643 static void mac_zoomwindow(WindowPtr window, short part) {
644
645     /* FIXME: do something */
646 }
647
648 /*
649  * Make the menus look right before the user gets to see them.
650  */
651 #if TARGET_API_MAC_CARBON
652 #define EnableItem EnableMenuItem
653 #define DisableItem DisableMenuItem
654 #endif
655 static void mac_adjustmenus(void) {
656     WindowPtr window;
657     MenuHandle menu;
658
659     window = FrontWindow();
660     menu = GetMenuHandle(mApple);
661     EnableItem(menu, 0);
662     EnableItem(menu, iAbout);
663
664     menu = GetMenuHandle(mFile);
665     EnableItem(menu, 0);
666     EnableItem(menu, iNew);
667     if (window != NULL)
668         EnableItem(menu, iClose);
669     else
670         DisableItem(menu, iClose);
671     EnableItem(menu, iQuit);
672
673     switch (mac_windowtype(window)) {
674       case wSettings:
675         DisableItem(menu, iSave); /* XXX enable if modified */
676         EnableItem(menu, iSaveAs);
677         EnableItem(menu, iDuplicate);
678         menu = GetMenuHandle(mEdit);
679         DisableItem(menu, 0);
680         break;
681       case wTerminal:
682         mac_adjusttermmenus(window);
683         break;
684       default:
685         DisableItem(menu, iSave);
686         DisableItem(menu, iSaveAs);
687         DisableItem(menu, iDuplicate);
688         menu = GetMenuHandle(mEdit);
689         DisableItem(menu, 0);
690         menu = GetMenuHandle(mWindow);
691         DisableItem(menu, 0); /* Until we get more than 1 item on it. */
692         break;
693     }
694     DrawMenuBar();
695 }
696
697 /*
698  * Make sure the right cursor's being displayed.
699  */
700 static void mac_adjustcursor(RgnHandle cursrgn) {
701     Point mouse;
702     WindowPtr window, front;
703     short part;
704 #if TARGET_API_MAC_CARBON
705     Cursor arrow;
706     RgnHandle visrgn;
707 #endif
708
709     GetMouse(&mouse);
710     LocalToGlobal(&mouse);
711     part = FindWindow(mouse, &window);
712     front = FrontWindow();
713     if (part != inContent || window == NULL || window != front) {
714         /* Cursor isn't in the front window, so switch to arrow */
715 #if TARGET_API_MAC_CARBON
716         GetQDGlobalsArrow(&arrow);
717         SetCursor(&arrow);
718 #else
719         SetCursor(&qd.arrow);
720 #endif
721         SetRectRgn(cursrgn, SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
722         if (front != NULL) {
723 #if TARGET_API_MAC_CARBON
724             visrgn = NewRgn();
725             GetPortVisibleRegion(GetWindowPort(front), visrgn);
726             DiffRgn(cursrgn, visrgn, cursrgn);
727             DisposeRgn(visrgn);
728 #else
729             DiffRgn(cursrgn, front->visRgn, cursrgn);
730 #endif
731         }
732     } else {
733         switch (mac_windowtype(window)) {
734           case wTerminal:
735             mac_adjusttermcursor(window, mouse, cursrgn);
736             break;
737           default:
738 #if TARGET_API_MAC_CARBON
739             GetQDGlobalsArrow(&arrow);
740             SetCursor(&arrow);
741             GetPortVisibleRegion(GetWindowPort(window), cursrgn);
742 #else
743             SetCursor(&qd.arrow);
744             CopyRgn(window->visRgn, cursrgn);
745 #endif
746             break;
747         }
748     }
749 }
750
751 pascal OSErr mac_aevt_quit(const AppleEvent *req, AppleEvent *reply,
752                                   long refcon)
753 {
754     DescType type;
755     Size size;
756
757     if (AEGetAttributePtr(req, keyMissedKeywordAttr, typeWildCard,
758                           &type, NULL, 0, &size) == noErr)
759         return errAEParamMissed;
760
761     borednow = 1;
762     return noErr;
763 }
764
765 void cleanup_exit(int status)
766 {
767
768 #if !TARGET_RT_MAC_CFM
769     if (mac_gestalts.encvvers != 0)
770         TerminateUnicodeConverter();
771 #endif
772     sk_cleanup();
773     exit(status);
774 }
775
776 void fatalbox(char *fmt, ...) {
777     va_list ap;
778     Str255 stuff;
779     
780     va_start(ap, fmt);
781     /* We'd like stuff to be a Pascal string */
782     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
783     va_end(ap);
784     ParamText(stuff, NULL, NULL, NULL);
785     StopAlert(128, NULL);
786     cleanup_exit(1);
787 }
788
789 void modalfatalbox(char *fmt, ...) {
790     va_list ap;
791     Str255 stuff;
792     
793     va_start(ap, fmt);
794     /* We'd like stuff to be a Pascal string */
795     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
796     va_end(ap);
797     ParamText(stuff, NULL, NULL, NULL);
798     StopAlert(128, NULL);
799     cleanup_exit(1);
800 }
801
802 /* This should only kill the current session, not the whole application. */
803 void connection_fatal(void *fontend, char *fmt, ...) {
804     va_list ap;
805     Str255 stuff;
806     
807     va_start(ap, fmt);
808     /* We'd like stuff to be a Pascal string */
809     stuff[0] = vsprintf((char *)(&stuff[1]), fmt, ap);
810     va_end(ap);
811     ParamText(stuff, NULL, NULL, NULL);
812     StopAlert(128, NULL);
813     cleanup_exit(1);
814 }
815
816 /* Null SSH agent client -- never finds an agent. */
817
818 int agent_exists(void)
819 {
820
821     return FALSE;
822 }
823
824 void agent_query(void *in, int inlen, void **out, int *outlen)
825 {
826
827     *out = NULL;
828     *outlen = 0;
829 }
830
831 /* Temporary null routines for testing. */
832
833 void verify_ssh_host_key(void *frontend, char *host, int port, char *keytype,
834                          char *keystr, char *fingerprint)
835 {
836
837 }
838
839 void askcipher(void *frontend, char *ciphername, int cs)
840 {
841
842 }
843
844 void old_keyfile_warning(void)
845 {
846
847 }
848
849 FontSpec platform_default_fontspec(char const *name)
850 {
851     FontSpec ret;
852     long smfs;
853
854     if (!strcmp(name, "Font")) {
855         smfs = GetScriptVariable(smSystemScript, smScriptMonoFondSize);
856         if (smfs == 0)
857             smfs = GetScriptVariable(smRoman, smScriptMonoFondSize);
858         if (smfs != 0) {
859             GetFontName(HiWord(smfs), ret.name);
860             if (ret.name[0] == 0)
861                 memcpy(ret.name, "\pMonaco", 7);
862             ret.size = LoWord(smfs);
863         } else {
864             memcpy(ret.name, "\pMonaco", 7);
865             ret.size = 9;
866         }
867         ret.face = 0;
868     } else {
869         ret.name[0] = 0;
870     }
871
872     return ret;
873 }
874
875 Filename platform_default_filename(const char *name)
876 {
877     Filename ret;
878     if (!strcmp(name, "LogFileName"))
879         FSMakeFSSpec(0, 0, "\pputty.log", &ret.fss);
880     else
881         memset(&ret, 0, sizeof(ret));
882     return ret;
883 }
884
885 char *platform_default_s(char const *name)
886 {
887     return NULL;
888 }
889
890 int platform_default_i(char const *name, int def)
891 {
892
893     /* Non-raw cut and paste of line-drawing chars works badly on the
894      * current Unix stub implementation of the Unicode functions.
895      * So I'm going to temporarily set the default to raw mode so
896      * that the failure mode isn't quite so drastically horrid.
897      * When Unicode comes in, this can all be put right. */
898     if (!strcmp(name, "RawCNP"))
899         return 1;
900     return def;
901 }
902
903 void platform_get_x11_auth(char *display, int *proto,
904                            unsigned char *data, int *datalen)
905 {
906     /* SGT: I have no idea whether Mac X servers need anything here. */
907 }
908
909 Filename filename_from_str(const char *str)
910 {
911     Filename ret;
912     Str255 tmp;
913
914     /* XXX This fails for filenames over 255 characters long. */
915     c2pstrcpy(tmp, str);
916     FSMakeFSSpec(0, 0, tmp, &ret.fss);
917     return ret;
918 }
919
920 /*
921  * Convert a filename to a string for display purposes.
922  * See pp 2-44--2-46 of IM:Files
923  *
924  * XXX static storage considered harmful
925  */
926 const char *filename_to_str(const Filename *fn)
927 {
928     CInfoPBRec pb;
929     Str255 dirname;
930     OSErr err;
931     static char *path = NULL;
932     char *newpath;
933
934     if (path != NULL) sfree(path);
935     path = smalloc(fn->fss.name[0]);
936     p2cstrcpy(path, fn->fss.name);
937     pb.dirInfo.ioNamePtr = dirname;
938     pb.dirInfo.ioVRefNum = fn->fss.vRefNum;
939     pb.dirInfo.ioDrParID = fn->fss.parID;
940     pb.dirInfo.ioFDirIndex = -1;
941     do {
942         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
943         err = PBGetCatInfoSync(&pb);
944
945         /* XXX Assume not A/UX */
946         newpath = smalloc(strlen(path) + dirname[0] + 2);
947         p2cstrcpy(newpath, dirname);
948         strcat(newpath, ":");
949         strcat(newpath, path);
950         sfree(path);
951         path = newpath;
952     } while (pb.dirInfo.ioDrDirID != fsRtDirID);
953     return path;
954 }
955
956 int filename_equal(Filename f1, Filename f2)
957 {
958
959     return f1.fss.vRefNum == f2.fss.vRefNum &&
960         f1.fss.parID == f2.fss.parID &&
961         f1.fss.name[0] == f2.fss.name[0] &&
962         memcmp(f1.fss.name + 1, f2.fss.name + 1, f1.fss.name[0]) == 0;
963 }
964
965 int filename_is_null(Filename fn)
966 {
967
968     return fn.fss.vRefNum == 0 && fn.fss.parID == 0 && fn.fss.name[0] == 0;
969 }
970
971 FILE *f_open(Filename fn, char const *mode)
972 {
973     short savevol;
974     long savedir;
975     char tmp[256];
976     FILE *ret;
977
978     HGetVol(NULL, &savevol, &savedir);
979     if (HSetVol(NULL, fn.fss.vRefNum, fn.fss.parID) == noErr) {
980         p2cstrcpy(tmp, fn.fss.name);
981         ret = fopen(tmp, mode);
982     } else
983         ret = NULL;
984     HSetVol(NULL, savevol, savedir);
985     return ret;
986 }
987
988 /*
989  * Local Variables:
990  * c-file-style: "simon"
991  * End:
992  */