Changeset 920


Ignore:
Timestamp:
Sep 25, 2006, 6:37:45 PM (15 years ago)
Author:
joshe
Message:

Merge nat-traversal branch to trunk.

Location:
trunk
Files:
48 edited
20 copied

Legend:

Unmodified
Added
Removed
  • trunk/Transmission.xcodeproj/project.pbxproj

    r850 r920  
    88
    99/* Begin PBXBuildFile section */
     10                3518E4A50AC620FC002ED3A2 /* PiecesWindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3518E4A30AC620FC002ED3A2 /* PiecesWindowController.h */; };
     11                3518E4A60AC620FC002ED3A2 /* PiecesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3518E4A40AC620FC002ED3A2 /* PiecesWindowController.m */; };
     12                3518E4D10AC62517002ED3A2 /* PiecesBack.tiff in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3518E4CD0AC62517002ED3A2 /* PiecesBack.tiff */; };
     13                3518E4D30AC62517002ED3A2 /* BoxBlue1.tiff in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3518E4CF0AC62517002ED3A2 /* BoxBlue1.tiff */; };
     14                3518E4D40AC62517002ED3A2 /* BoxBlue2.tiff in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3518E4D00AC62517002ED3A2 /* BoxBlue2.tiff */; };
     15                3518E4D70AC6253F002ED3A2 /* PiecesWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = 3518E4D50AC6253F002ED3A2 /* PiecesWindow.nib */; };
     16                3518E4FB0AC62832002ED3A2 /* PiecesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3518E4A40AC620FC002ED3A2 /* PiecesWindowController.m */; };
     17                3518E5210AC62A29002ED3A2 /* PiecesBack.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3518E4CD0AC62517002ED3A2 /* PiecesBack.tiff */; };
     18                3518E5230AC62A2A002ED3A2 /* BoxBlue2.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3518E4D00AC62517002ED3A2 /* BoxBlue2.tiff */; };
     19                3518E5240AC62A2B002ED3A2 /* BoxBlue1.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3518E4CF0AC62517002ED3A2 /* BoxBlue1.tiff */; };
     20                3518E5290AC62A55002ED3A2 /* BoxBlue3.tiff in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3518E5270AC62A55002ED3A2 /* BoxBlue3.tiff */; };
     21                3518E52A0AC62A55002ED3A2 /* BoxWhite.tiff in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3518E5280AC62A55002ED3A2 /* BoxWhite.tiff */; };
     22                3518E52B0AC62A57002ED3A2 /* BoxWhite.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3518E5280AC62A55002ED3A2 /* BoxWhite.tiff */; };
     23                3518E52C0AC62A57002ED3A2 /* BoxBlue3.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3518E5270AC62A55002ED3A2 /* BoxBlue3.tiff */; };
     24                3518E5770AC63262002ED3A2 /* BoxGreen.tiff in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3518E5760AC63262002ED3A2 /* BoxGreen.tiff */; };
     25                3518E57B0AC632EA002ED3A2 /* BoxGreen.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 3518E5760AC63262002ED3A2 /* BoxGreen.tiff */; };
     26                35B037A70AC59BC600A10FDF /* Check.png in CopyFiles */ = {isa = PBXBuildFile; fileRef = 35B037A60AC59BC600A10FDF /* Check.png */; };
     27                35B037B60AC59C4000A10FDF /* Check.png in Resources */ = {isa = PBXBuildFile; fileRef = 35B037A60AC59BC600A10FDF /* Check.png */; };
     28                35B037FB0AC5B53800A10FDF /* ResumeNoWaitOn.png in CopyFiles */ = {isa = PBXBuildFile; fileRef = 35B037F90AC5B53800A10FDF /* ResumeNoWaitOn.png */; };
     29                35B037FC0AC5B53800A10FDF /* ResumeNoWaitOff.png in CopyFiles */ = {isa = PBXBuildFile; fileRef = 35B037FA0AC5B53800A10FDF /* ResumeNoWaitOff.png */; };
     30                35B038130AC5B6EB00A10FDF /* ResumeNoWaitOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 35B037F90AC5B53800A10FDF /* ResumeNoWaitOn.png */; };
     31                35B038140AC5B6EC00A10FDF /* ResumeNoWaitOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 35B037FA0AC5B53800A10FDF /* ResumeNoWaitOff.png */; };
    1032                4D043A7F090AE979009FEDA8 /* TransmissionDocument.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4D043A7E090AE979009FEDA8 /* TransmissionDocument.icns */; };
    1133                4D118E1A08CB46B20033958F /* PrefsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D118E1908CB46B20033958F /* PrefsController.m */; };
     
    5779                4DA6FDC5091141AD00450CB1 /* ResumeOff.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC3091141AD00450CB1 /* ResumeOff.png */; };
    5880                4DA6FDC6091141AD00450CB1 /* ResumeOn.png in Resources */ = {isa = PBXBuildFile; fileRef = 4DA6FDC4091141AD00450CB1 /* ResumeOn.png */; };
     81                4DAB87C50ABE1F730081CF7E /* xml.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DAB87BD0ABE1F730081CF7E /* xml.h */; };
     82                4DAB87C60ABE1F730081CF7E /* xml.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DAB87BE0ABE1F730081CF7E /* xml.c */; };
     83                4DAB87C70ABE1F730081CF7E /* upnp.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DAB87BF0ABE1F730081CF7E /* upnp.h */; };
     84                4DAB87C80ABE1F730081CF7E /* upnp.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DAB87C00ABE1F730081CF7E /* upnp.c */; };
     85                4DAB87C90ABE1F730081CF7E /* natpmp.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DAB87C10ABE1F730081CF7E /* natpmp.h */; };
     86                4DAB87CA0ABE1F730081CF7E /* natpmp.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DAB87C20ABE1F730081CF7E /* natpmp.c */; };
     87                4DAB87CB0ABE1F730081CF7E /* http.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DAB87C30ABE1F730081CF7E /* http.h */; };
     88                4DAB87CC0ABE1F730081CF7E /* http.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DAB87C40ABE1F730081CF7E /* http.c */; };
    5989                4DCCBB3E09C3D71100D3CABF /* TorrentCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DCCBB3C09C3D71100D3CABF /* TorrentCell.m */; };
    6090                4DDBB71C09E16BF100284745 /* transmissioncli.c in Sources */ = {isa = PBXBuildFile; fileRef = 4DDBB71B09E16BF100284745 /* transmissioncli.c */; };
     
    179209                                A25FCDDF0A37695F002BCBBE /* PauseSelected.png in CopyFiles */,
    180210                                A25FCDE00A37695F002BCBBE /* ResumeSelected.png in CopyFiles */,
     211                                35B037A70AC59BC600A10FDF /* Check.png in CopyFiles */,
     212                                35B037FB0AC5B53800A10FDF /* ResumeNoWaitOn.png in CopyFiles */,
     213                                35B037FC0AC5B53800A10FDF /* ResumeNoWaitOff.png in CopyFiles */,
     214                                3518E4D10AC62517002ED3A2 /* PiecesBack.tiff in CopyFiles */,
     215                                3518E4D30AC62517002ED3A2 /* BoxBlue1.tiff in CopyFiles */,
     216                                3518E4D40AC62517002ED3A2 /* BoxBlue2.tiff in CopyFiles */,
     217                                3518E5290AC62A55002ED3A2 /* BoxBlue3.tiff in CopyFiles */,
     218                                3518E52A0AC62A55002ED3A2 /* BoxWhite.tiff in CopyFiles */,
     219                                3518E5770AC63262002ED3A2 /* BoxGreen.tiff in CopyFiles */,
    181220                        );
    182221                        runOnlyForDeploymentPostprocessing = 0;
     
    211250                29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
    212251                32CA4F630368D1EE00C91783 /* Transmission_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Transmission_Prefix.pch; path = macosx/Transmission_Prefix.pch; sourceTree = "<group>"; };
     252                3518E4A30AC620FC002ED3A2 /* PiecesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PiecesWindowController.h; sourceTree = "<group>"; };
     253                3518E4A40AC620FC002ED3A2 /* PiecesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PiecesWindowController.m; sourceTree = "<group>"; };
     254                3518E4CD0AC62517002ED3A2 /* PiecesBack.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = PiecesBack.tiff; path = macosx/Images/PiecesBack.tiff; sourceTree = "<group>"; };
     255                3518E4CF0AC62517002ED3A2 /* BoxBlue1.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BoxBlue1.tiff; path = macosx/Images/BoxBlue1.tiff; sourceTree = "<group>"; };
     256                3518E4D00AC62517002ED3A2 /* BoxBlue2.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BoxBlue2.tiff; path = macosx/Images/BoxBlue2.tiff; sourceTree = "<group>"; };
     257                3518E4D60AC6253F002ED3A2 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = macosx/English.lproj/PiecesWindow.nib; sourceTree = "<group>"; };
     258                3518E5270AC62A55002ED3A2 /* BoxBlue3.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BoxBlue3.tiff; path = macosx/Images/BoxBlue3.tiff; sourceTree = "<group>"; };
     259                3518E5280AC62A55002ED3A2 /* BoxWhite.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BoxWhite.tiff; path = macosx/Images/BoxWhite.tiff; sourceTree = "<group>"; };
     260                3518E5760AC63262002ED3A2 /* BoxGreen.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BoxGreen.tiff; path = macosx/Images/BoxGreen.tiff; sourceTree = "<group>"; };
     261                35B037A60AC59BC600A10FDF /* Check.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Check.png; path = macosx/Images/Check.png; sourceTree = "<group>"; };
     262                35B037F90AC5B53800A10FDF /* ResumeNoWaitOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeNoWaitOn.png; path = macosx/Images/ResumeNoWaitOn.png; sourceTree = "<group>"; };
     263                35B037FA0AC5B53800A10FDF /* ResumeNoWaitOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeNoWaitOff.png; path = macosx/Images/ResumeNoWaitOff.png; sourceTree = "<group>"; };
    213264                4D043A7E090AE979009FEDA8 /* TransmissionDocument.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = TransmissionDocument.icns; path = macosx/Images/TransmissionDocument.icns; sourceTree = "<group>"; };
    214265                4D118E1808CB46B20033958F /* PrefsController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PrefsController.h; path = macosx/PrefsController.h; sourceTree = "<group>"; };
     
    263314                4DA6FDC3091141AD00450CB1 /* ResumeOff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOff.png; path = macosx/Images/ResumeOff.png; sourceTree = "<group>"; };
    264315                4DA6FDC4091141AD00450CB1 /* ResumeOn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ResumeOn.png; path = macosx/Images/ResumeOn.png; sourceTree = "<group>"; };
     316                4DAB87BD0ABE1F730081CF7E /* xml.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = xml.h; path = libtransmission/xml.h; sourceTree = "<group>"; };
     317                4DAB87BE0ABE1F730081CF7E /* xml.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = xml.c; path = libtransmission/xml.c; sourceTree = "<group>"; };
     318                4DAB87BF0ABE1F730081CF7E /* upnp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = upnp.h; path = libtransmission/upnp.h; sourceTree = "<group>"; };
     319                4DAB87C00ABE1F730081CF7E /* upnp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = upnp.c; path = libtransmission/upnp.c; sourceTree = "<group>"; };
     320                4DAB87C10ABE1F730081CF7E /* natpmp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = natpmp.h; path = libtransmission/natpmp.h; sourceTree = "<group>"; };
     321                4DAB87C20ABE1F730081CF7E /* natpmp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = natpmp.c; path = libtransmission/natpmp.c; sourceTree = "<group>"; };
     322                4DAB87C30ABE1F730081CF7E /* http.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = http.h; path = libtransmission/http.h; sourceTree = "<group>"; };
     323                4DAB87C40ABE1F730081CF7E /* http.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = http.c; path = libtransmission/http.c; sourceTree = "<group>"; };
    265324                4DCCBB3C09C3D71100D3CABF /* TorrentCell.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = TorrentCell.m; path = macosx/TorrentCell.m; sourceTree = "<group>"; };
    266325                4DCCBB3D09C3D71100D3CABF /* TorrentCell.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = TorrentCell.h; path = macosx/TorrentCell.h; sourceTree = "<group>"; };
    267                 4DDBB71909E16BAE00284745 /* transmissioncli */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = transmissioncli; sourceTree = BUILT_PRODUCTS_DIR; };
     326                4DDBB71909E16BAE00284745 /* transmissioncli */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = transmissioncli; sourceTree = BUILT_PRODUCTS_DIR; };
    268327                4DDBB71B09E16BF100284745 /* transmissioncli.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = transmissioncli.c; path = cli/transmissioncli.c; sourceTree = "<group>"; };
    269328                4DDFDD20099A5D8E00189D81 /* DownloadBadge.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = DownloadBadge.png; path = macosx/Images/DownloadBadge.png; sourceTree = "<group>"; };
     
    394453                        isa = PBXGroup;
    395454                        children = (
     455                                3518E4A30AC620FC002ED3A2 /* PiecesWindowController.h */,
     456                                3518E4A40AC620FC002ED3A2 /* PiecesWindowController.m */,
    396457                                A2A306530AAD24A80049E2AC /* UKFileWatcher.h */,
    397458                                A2A306540AAD24A80049E2AC /* UKFileWatcher.m */,
     
    464525                                A259316A0A73B2CC002F4FE7 /* Transmission Help */,
    465526                                A2F8951E0A2D4BA500ED2127 /* Credits.rtf */,
     527                                3518E4CD0AC62517002ED3A2 /* PiecesBack.tiff */,
     528                                3518E4CF0AC62517002ED3A2 /* BoxBlue1.tiff */,
     529                                3518E4D00AC62517002ED3A2 /* BoxBlue2.tiff */,
     530                                3518E5270AC62A55002ED3A2 /* BoxBlue3.tiff */,
     531                                3518E5280AC62A55002ED3A2 /* BoxWhite.tiff */,
     532                                3518E5760AC63262002ED3A2 /* BoxGreen.tiff */,
    466533                                A2305AA40A3DCCEF00AB2D77 /* ProgressBarEndAdvanced.png */,
    467534                                A2305AA50A3DCCEF00AB2D77 /* ProgressBarEndBlue.png */,
     
    474541                                A2305A7E0A3DC9E400AB2D77 /* ProgressBarGray.png */,
    475542                                A2305A7F0A3DC9E400AB2D77 /* ProgressBarGreen.png */,
     543                                35B037A60AC59BC600A10FDF /* Check.png */,
    476544                                A260C9AB0AA3B8D700FDC1B7 /* Error.tiff */,
    477545                                A2D4F0840A915F7200890C32 /* GreenDot.tiff */,
     
    487555                                4DF7500708A103AD007B0D70 /* Open.png */,
    488556                                4DF7500908A103AD007B0D70 /* Remove.png */,
     557                                35B037F90AC5B53800A10FDF /* ResumeNoWaitOn.png */,
     558                                35B037FA0AC5B53800A10FDF /* ResumeNoWaitOff.png */,
    489559                                4D6DAAC4090CE00500F43C22 /* RevealOff.png */,
    490560                                4D6DAAC5090CE00500F43C22 /* RevealOn.png */,
     
    530600                                A253F7290A699373008EE24F /* FilterButtonSelectedRight.png */,
    531601                                A2912C520A2956E80097A0CA /* PrefsWindow.nib */,
     602                                3518E4D50AC6253F002ED3A2 /* PiecesWindow.nib */,
    532603                        );
    533604                        name = Resources;
     
    584655                                4D1838BA09DEC0430047D688 /* completion.c */,
    585656                                4D1838BB09DEC0430047D688 /* clients.h */,
     657                                4DAB87BD0ABE1F730081CF7E /* xml.h */,
     658                                4DAB87BE0ABE1F730081CF7E /* xml.c */,
     659                                4DAB87BF0ABE1F730081CF7E /* upnp.h */,
     660                                4DAB87C00ABE1F730081CF7E /* upnp.c */,
     661                                4DAB87C10ABE1F730081CF7E /* natpmp.h */,
     662                                4DAB87C20ABE1F730081CF7E /* natpmp.c */,
     663                                4DAB87C30ABE1F730081CF7E /* http.h */,
     664                                4DAB87C40ABE1F730081CF7E /* http.c */,
    586665                        );
    587666                        name = libtransmission;
     
    650729                                A26D450B0A0503AC00A10BB3 /* peermessages.h in Headers */,
    651730                                A2BD40070A09BBEA008CCE96 /* bencode.h in Headers */,
     731                                4DAB87C50ABE1F730081CF7E /* xml.h in Headers */,
     732                                4DAB87C70ABE1F730081CF7E /* upnp.h in Headers */,
     733                                4DAB87C90ABE1F730081CF7E /* natpmp.h in Headers */,
     734                                4DAB87CB0ABE1F730081CF7E /* http.h in Headers */,
     735                                3518E4A50AC620FC002ED3A2 /* PiecesWindowController.h in Headers */,
    652736                        );
    653737                        runOnlyForDeploymentPostprocessing = 0;
     
    800884                                A21567ED0A9A5034004DECD6 /* MessageWindow.nib in Resources */,
    801885                                A260C9AC0AA3B8D700FDC1B7 /* Error.tiff in Resources */,
     886                                35B037B60AC59C4000A10FDF /* Check.png in Resources */,
     887                                35B038130AC5B6EB00A10FDF /* ResumeNoWaitOn.png in Resources */,
     888                                35B038140AC5B6EC00A10FDF /* ResumeNoWaitOff.png in Resources */,
     889                                3518E4D70AC6253F002ED3A2 /* PiecesWindow.nib in Resources */,
     890                                3518E5210AC62A29002ED3A2 /* PiecesBack.tiff in Resources */,
     891                                3518E5230AC62A2A002ED3A2 /* BoxBlue2.tiff in Resources */,
     892                                3518E5240AC62A2B002ED3A2 /* BoxBlue1.tiff in Resources */,
     893                                3518E52B0AC62A57002ED3A2 /* BoxWhite.tiff in Resources */,
     894                                3518E52C0AC62A57002ED3A2 /* BoxBlue3.tiff in Resources */,
     895                                3518E57B0AC632EA002ED3A2 /* BoxGreen.tiff in Resources */,
    802896                        );
    803897                        runOnlyForDeploymentPostprocessing = 0;
     
    825919                                4D1838FB09DEC4380047D688 /* utils.c in Sources */,
    826920                                4D1838FD09DEC4380047D688 /* transmission.c in Sources */,
     921                                4DAB87C60ABE1F730081CF7E /* xml.c in Sources */,
     922                                4DAB87C80ABE1F730081CF7E /* upnp.c in Sources */,
     923                                4DAB87CA0ABE1F730081CF7E /* natpmp.c in Sources */,
     924                                4DAB87CC0ABE1F730081CF7E /* http.c in Sources */,
     925                                3518E4A60AC620FC002ED3A2 /* PiecesWindowController.m in Sources */,
    827926                        );
    828927                        runOnlyForDeploymentPostprocessing = 0;
     
    859958                                A2A306600AAD24A80049E2AC /* UKKQueue.m in Sources */,
    860959                                A2A306620AAD24A80049E2AC /* UKMainThreadProxy.m in Sources */,
     960                                3518E4FB0AC62832002ED3A2 /* PiecesWindowController.m in Sources */,
    861961                        );
    862962                        runOnlyForDeploymentPostprocessing = 0;
     
    892992                        );
    893993                        name = MainMenu.nib;
     994                        sourceTree = "<group>";
     995                };
     996                3518E4D50AC6253F002ED3A2 /* PiecesWindow.nib */ = {
     997                        isa = PBXVariantGroup;
     998                        children = (
     999                                3518E4D60AC6253F002ED3A2 /* English */,
     1000                        );
     1001                        name = PiecesWindow.nib;
    8941002                        sourceTree = "<group>";
    8951003                };
  • trunk/cli/transmissioncli.1

    r261 r920  
    2727.Op Fl s Ar torrent-file
    2828.Op Fl v Ar level
     29.Op Fl n
    2930.Op Fl p Ar port
    3031.Op Fl u Ar upload-rate
     
    5152Sets debugging options.  The current range is 0-2, with the highest
    5253level producing the most output.  The default is 0.
     54.It Fl n, Fl -nat-traversal
     55Attempt to use the NAT-PMP and UPnP IGD protocols to establish a port
     56mapping for allowing incoming peer connections.
    5357.It Fl p, -port Ar port
    5458Specifies an alternate port for the client to listen on.  The default is
  • trunk/cli/transmissioncli.c

    r310 r920  
    3838"Usage: %s [options] file.torrent [options]\n\n" \
    3939"Options:\n" \
     40"  -d, --download <int> Maximum download rate (-1 = no limit, default = -1)\n"\
     41"  -f, --finish <shell script> Command you wish to run on completion\n" \
    4042"  -h, --help           Print this help and exit\n" \
    4143"  -i, --info           Print metainfo and exit\n" \
     44"  -n  --nat-traversal  Attempt NAT traversal using NAT-PMP or UPnP IGD\n" \
     45"  -p, --port <int>     Port we should listen on (default = %d)\n" \
    4246"  -s, --scrape         Print counts of seeders/leechers and exit\n" \
    43 "  -v, --verbose <int>  Verbose level (0 to 2, default = 0)\n" \
    44 "  -p, --port <int>     Port we should listen on (default = %d)\n" \
    4547"  -u, --upload <int>   Maximum upload rate (-1 = no limit, default = 20)\n" \
    46 "  -d, --download <int> Maximum download rate (-1 = no limit, default = -1)\n" \
    47 "  -f, --finish <shell script> Command you wish to run on completion\n"
     48"  -v, --verbose <int>  Verbose level (0 to 2, default = 0)\n"
    4849
    4950static int           showHelp      = 0;
     
    5657static char          * torrentPath = NULL;
    5758static volatile char mustDie       = 0;
     59static int           natTraversal  = 0;
    5860
    5961static char          * finishCall   = NULL;
     
    6466int main( int argc, char ** argv )
    6567{
    66     int i, error;
     68    int i, error, nat;
    6769    tr_handle_t  * h;
    6870    tr_torrent_t * tor;
     
    164166    tr_setUploadLimit( h, uploadLimit );
    165167    tr_setDownloadLimit( h, downloadLimit );
     168
     169    if( natTraversal )
     170    {
     171        tr_natTraversalEnable( h );
     172    }
     173    else
     174    {
     175        tr_natTraversalDisable( h );
     176    }
    166177   
    167178    tr_torrentSetFolder( tor, "." );
     
    201212        memset( &string[chars], ' ', 79 - chars );
    202213        string[79] = '\0';
    203         fprintf( stderr, "\r%s", string );
     214        //fprintf( stderr, "\r%s", string );
    204215
    205216        if( s->error & TR_ETRACKER )
     
    219230    fprintf( stderr, "\n" );
    220231
    221     /* Try for 5 seconds to notice the tracker that we are leaving */
     232    /* Try for 5 seconds to notify the tracker that we are leaving
     233       and to delete any port mappings for nat traversal */
    222234    tr_torrentStop( tor );
     235    tr_natTraversalDisable( h );
    223236    for( i = 0; i < 10; i++ )
    224237    {
    225238        s = tr_torrentStat( tor );
    226         if( s->status & TR_STATUS_PAUSE )
    227         {
    228             /* The 'stopped' message was sent */
     239        nat = tr_natTraversalStatus( h );
     240        if( s->status & TR_STATUS_PAUSE && TR_NAT_TRAVERSAL_DISABLED == nat )
     241        {
     242            /* The 'stopped' tracker message was sent
     243               and port mappings were deleted */
    229244            break;
    230245        }
     
    254269            { "download", required_argument, NULL, 'd' },
    255270            { "finish",   required_argument, NULL, 'f' },
     271            { "nat-traversal", no_argument,  NULL, 'n' },
    256272            { 0, 0, 0, 0} };
    257273
    258274        int c, optind = 0;
    259         c = getopt_long( argc, argv, "hisv:p:u:d:f:", long_options, &optind );
     275        c = getopt_long( argc, argv, "hisv:p:u:d:f:n", long_options, &optind );
    260276        if( c < 0 )
    261277        {
     
    287303            case 'f':
    288304                finishCall = optarg;
     305                break;
     306            case 'n':
     307                natTraversal = 1;
    289308                break;
    290309            default:
  • trunk/gtk/conf.c

    r760 r920  
    359359  GError *err;
    360360  char *datastr;
    361   size_t len;
     361  int len;
    362362  gsize written;
    363363
  • trunk/gtk/conf.h

    r804 r920  
    6060#define PREF_ADDIPC             "add-behavior-ipc"
    6161#define PREF_MSGLEVEL           "message-level"
     62#define PREF_NAT                "use-nat-traversal"
    6263
    6364#endif /* TG_CONF_H */
  • trunk/gtk/dialogs.c

    r804 r920  
    4242#define DEF_UPLIMIT             20
    4343#define DEF_USEUPLIMIT          TRUE
     44#define DEF_NAT                 TRUE
    4445
    4546struct prefdata {
     
    171172   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
    172173   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
    173   const unsigned int rowcount = 8;
     174  const unsigned int rowcount = 9;
    174175  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
    175176  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
     177  GtkWidget *natcheck = gtk_check_button_new_with_mnemonic(
     178    _("Use NAT _Traversal (NAT-PMP and UPnP)"));
    176179  GtkWidget *dirstr = gtk_file_chooser_button_new(
    177180    _("Choose a download directory"),
     
    197200  GtkTreeIter iter;
    198201  GtkCellRenderer *rend;
     202  gboolean boolval;
     203  int intval;
    199204
    200205  g_free(title);
     
    207212
    208213  data->prefwidgets = makeglist(portnum, lim[0].on, lim[0].num, lim[1].on,
    209     lim[1].num, dirstr, addstd, addipc, NULL);
     214    lim[1].num, dirstr, addstd, addipc, natcheck, NULL);
    210215  data->parent = parent;
    211216  data->back = back;
     
    252257  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
    253258  gtk_table_attach_defaults(GTK_TABLE(table), portnum,         1, 2, RN(ii));
     259  ii++;
     260
     261  /* NAT traversal checkbox */
     262  intval = tr_natTraversalStatus(tr_backend_handle(back));
     263  boolval = !TR_NAT_TRAVERSAL_IS_DISABLED( intval );
     264  setupprefwidget(natcheck, PREF_NAT, boolval);
     265  gtk_table_attach_defaults(GTK_TABLE(table), natcheck,        0, 2, RN(ii));
    254266  ii++;
    255267
     
    341353    }
    342354
     355    applyprefs(data->back);
    343356    /* XXX would be nice to have errno strings, are they printed to stdout? */
    344 
    345     tr_setBindPort(tr_backend_handle(data->back),
    346                    strtol(cf_getpref(PREF_PORT), NULL, 10));
    347     setlimit(data->back);
    348357  }
    349358
     
    353362
    354363void
    355 setlimit(TrBackend *back) {
     364applyprefs(TrBackend *back) {
    356365  struct { void (*func)(tr_handle_t*, int);
    357366    const char *use; const char *num; gboolean defuse; long def; } lim[] = {
     
    362371  };
    363372  const char *pref;
    364   unsigned int ii;
     373  int ii;
    365374  tr_handle_t *tr = tr_backend_handle(back);
    366 
    367   for(ii = 0; ii < ALEN(lim); ii++) {
     375  gboolean boolval;
     376
     377  /* set upload and download limits */
     378  for(ii = 0; ii < (int)ALEN(lim); ii++) {
    368379    pref = cf_getpref(lim[ii].use);
    369380    if(!(NULL == pref ? lim[ii].defuse : strbool(pref)))
     
    374385    }
    375386  }
     387
     388  /* set the listening port */
     389  if(NULL != (pref = cf_getpref(PREF_PORT)) &&
     390     0 < (ii = strtol(pref, NULL, 10)) && 0xffff >= ii)
     391    tr_setBindPort(tr, ii);
     392
     393  /* enable/disable NAT traversal */
     394  boolval = (NULL == (pref = cf_getpref(PREF_NAT)) ? DEF_NAT : strbool(pref));
     395  if( boolval )
     396    tr_natTraversalEnable(tr);
     397  else
     398    tr_natTraversalDisable(tr);
    376399}
    377400
  • trunk/gtk/dialogs.h

    r804 r920  
    3333makeprefwindow(GtkWindow *parent, TrBackend *back);
    3434
    35 /* set the upload limit based on saved prefs */
     35/* set various things based on saved prefs */
    3636void
    37 setlimit(TrBackend *back);
     37applyprefs(TrBackend *back);
    3838
    3939/* show the "add a torrent" dialog */
  • trunk/gtk/ipc.c

    r760 r920  
    264264send_msg(struct constate *con, const char *name, benc_val_t *val) {
    265265  char *buf;
    266   size_t used, total;
     266  int used, total;
    267267  benc_val_t dict;
    268268  char stupid;
  • trunk/gtk/main.c

    r918 r920  
    178178  TrBackend *back;
    179179  benc_val_t *state;
    180   const char *pref;
    181   long intval;
    182180  GList *argfiles;
    183181  gboolean didinit, didlock;
     
    234232      back = tr_backend_new();
    235233
    236       /* set the upload limit */
    237       setlimit(back);
    238 
    239       /* set the listening port */
    240       if(NULL != (pref = cf_getpref(PREF_PORT)) &&
    241          0 < (intval = strtol(pref, NULL, 10)) && 0xffff >= intval)
    242         tr_setBindPort(tr_backend_handle(back), intval);
     234      /* apply a few prefs */
     235      applyprefs(back);
    243236
    244237      makewind(mainwind, back, state, argfiles);
     
    524517  tr_backend_stop_torrents(data->back);
    525518
     519  /* shut down nat traversal */
     520  tr_natTraversalDisable(tr_backend_handle(data->back));
     521
    526522  /* set things up to wait for torrents to stop */
    527523  edata = g_new0(struct exitdata, 1);
     
    545541exitcheck(gpointer gdata) {
    546542  struct exitdata *data = gdata;
    547 
    548   /* keep going if we still have torrents and haven't hit the exit timeout */
    549   if(time(NULL) - data->started < TRACKER_EXIT_TIMEOUT &&
    550      !tr_backend_torrents_stopped(data->cbdata->back)) {
     543  int natstat = tr_natTraversalStatus(tr_backend_handle(data->cbdata->back));
     544
     545  /* keep going if we haven't hit the exit timeout and
     546     we either have torrents left or nat traversal is stopping */
     547  if( time( NULL ) - data->started < TRACKER_EXIT_TIMEOUT &&
     548      ( !tr_backend_torrents_stopped( data->cbdata->back ) &&
     549        TR_NAT_TRAVERSAL_DISABLED != natstat ) ) {
    551550    updatemodel(data->cbdata);
    552551    return TRUE;
  • trunk/libtransmission/bencode.c

    r543 r920  
    2626
    2727#define LIST_SIZE   20
    28 #define OUTBUF_SIZE 100
    29 
    30 static int tr_bencSprintf( char ** buf, size_t * used, size_t * max,
    31                            char * format, ... )
    32 #ifdef __GNUC__
    33     __attribute__ ((format (printf, 4, 5)))
    34 #endif
    35     ;
    36 
    37 int _tr_bencLoad( char * buf, size_t len, benc_val_t * val, char ** end )
     28
     29int _tr_bencLoad( char * buf, int len, benc_val_t * val, char ** end )
    3830{
    3931    char * p, * e, * foo;
     
    9082        cur              = &buf[1];
    9183        str_expected     = 1;
    92         while( (size_t)(cur - buf) < len && cur[0] != 'e' )
     84        while( cur - buf < len && cur[0] != 'e' )
    9385        {
    9486            if( val->val.l.count == val->val.l.alloc )
     
    140132
    141133        if( p != e || 0 > val->val.s.i ||
    142             (size_t)(val->val.s.i) > len - ((p + 1) - buf) )
     134            val->val.s.i > len - ((p + 1) - buf) )
    143135        {
    144136            return 1;
     
    241233}
    242234
    243 char * tr_bencSaveMalloc( benc_val_t * val, size_t * len )
     235char * tr_bencSaveMalloc( benc_val_t * val, int * len )
    244236{
    245237    char * buf   = NULL;
    246     size_t alloc = 0;
     238    int alloc = 0;
    247239
    248240    *len = 0;
     
    260252}
    261253
    262 int tr_bencSave( benc_val_t * val, char ** buf, size_t * used, size_t * max )
     254int tr_bencSave( benc_val_t * val, char ** buf, int * used, int * max )
    263255{
    264256    int ii;   
     
    267259    {
    268260        case TYPE_INT:
    269             if( tr_bencSprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
     261            if( tr_sprintf( buf, used, max, "i%"PRIu64"e", val->val.i ) )
    270262            {
    271263                return 1;
     
    278270                return 1;
    279271            }
    280             if( tr_bencSprintf( buf, used, max, "%i:%s",
    281                                 val->val.s.i, val->val.s.s ) )
     272            if( tr_sprintf( buf, used, max, "%i:%s",
     273                            val->val.s.i, val->val.s.s ) )
    282274            {
    283275                return 1;
     
    287279        case TYPE_LIST:
    288280        case TYPE_DICT:
    289             if( tr_bencSprintf( buf, used, max,
    290                                 (TYPE_LIST == val->type ? "l" : "d") ) )
     281            if( tr_sprintf( buf, used, max,
     282                            (TYPE_LIST == val->type ? "l" : "d") ) )
    291283            {
    292284                return 1;
     
    299291                }
    300292            }
    301             if( tr_bencSprintf( buf, used, max, "e" ) )
     293            if( tr_sprintf( buf, used, max, "e" ) )
    302294            {
    303295                return 1;
     
    308300    return 0;
    309301}
    310 
    311 static int tr_bencSprintf( char ** buf, size_t * used, size_t * max,
    312                            char * format, ... )
    313 {
    314     va_list ap;
    315     int     want;
    316     char  * newbuf;
    317 
    318     va_start( ap, format );
    319     want = vsnprintf( NULL, 0, format, ap );
    320     va_end(ap);
    321 
    322     while( *used + want + 1 > *max )
    323     {
    324         *max += OUTBUF_SIZE;
    325         newbuf = realloc( *buf, *max );
    326         if( NULL == newbuf )
    327         {
    328             return 1;
    329         }
    330         *buf = newbuf;
    331     }
    332 
    333     va_start( ap, format );
    334     *used += vsnprintf( *buf + *used, *max - *used, format, ap );
    335     va_end( ap );
    336 
    337     return 0;
    338 }
  • trunk/libtransmission/bencode.h

    r261 r920  
    5353
    5454#define tr_bencLoad(b,l,v,e) _tr_bencLoad((char*)(b),(l),(v),(char**)(e))
    55 int          _tr_bencLoad( char * buf, size_t len, benc_val_t * val,
     55int          _tr_bencLoad( char * buf, int len, benc_val_t * val,
    5656                           char ** end );
    5757void         tr_bencPrint( benc_val_t * val );
    5858void         tr_bencFree( benc_val_t * val );
    5959benc_val_t * tr_bencDictFind( benc_val_t * val, char * key );
    60 char *       tr_bencSaveMalloc( benc_val_t * val, size_t * len );
     60char *       tr_bencSaveMalloc( benc_val_t * val, int * len );
    6161int          tr_bencSave( benc_val_t * val, char ** buf,
    62                           size_t * used, size_t * max );
     62                          int * used, int * max );
    6363
    6464#endif
  • trunk/libtransmission/fastresume.h

    r326 r920  
    249249    {
    250250        tr_inf( "Wrong size for resume file (%d bytes, %d expected)",
    251                 ftell( file ), size );
     251                (int)ftell( file ), size );
    252252        fclose( file );
    253253        return 1;
  • trunk/libtransmission/inout.c

    r723 r920  
    417417    {
    418418        /* Should not happen */
    419         tr_err( "readOrWriteBytes: offset out of range (%lld, %d, %d)",
     419        tr_err( "readOrWriteBytes: offset out of range (%"PRIu64", %d, %d)",
    420420                offset, size, isWrite );
    421421        goto fail;
  • trunk/libtransmission/internal.h

    r788 r920  
    2929   That is probably ugly to put them all here, but it is sooo
    3030   convenient */
     31#if ( defined( __unix__ ) || defined( unix ) ) && !defined( USG )
     32#include <sys/param.h>
     33#endif
    3134#include <stdio.h>
    3235#include <stdarg.h>
     
    5154#ifdef BEOS_NETSERVER
    5255#  define in_port_t uint16_t
     56#  define socklen_t uint32_t
    5357#else
    5458#  include <arpa/inet.h>
    5559#endif
    5660
     61#ifndef INADDR_NONE
     62#define INADDR_NONE             0xffffffff
     63#endif
     64
    5765#ifdef __GNUC__
    5866#  define UNUSED __attribute__((unused))
     67#  define PRINTF( fmt, args ) __attribute__((format (printf, fmt, args)))
    5968#else
    6069#  define UNUSED
     70#  define PRINTF( fmt, args )
    6171#endif
    6272
     
    108118typedef struct tr_completion_s tr_completion_t;
    109119
     120typedef enum { TR_OK, TR_ERROR, TR_WAIT } tr_tristate_t;
     121
    110122#include "platform.h"
    111123#include "bencode.h"
     
    119131#include "clients.h"
    120132#include "choking.h"
     133#include "natpmp.h"
     134#include "upnp.h"
     135#include "http.h"
     136#include "xml.h"
    121137
    122138struct tr_torrent_s
     
    188204    tr_fd_t      * fdlimit;
    189205    tr_choking_t * choking;
     206    tr_natpmp_t  * natpmp;
     207    tr_upnp_t    * upnp;
    190208
    191209    int            bindPort;
  • trunk/libtransmission/metainfo.c

    r786 r920  
    7070    if( sb.st_size > TORRENT_MAX_SIZE )
    7171    {
    72         tr_err( "Torrent file is too big (%d bytes)", sb.st_size );
     72        tr_err( "Torrent file is too big (%d bytes)", (int)sb.st_size );
    7373        return 1;
    7474    }
  • trunk/libtransmission/net.c

    r791 r920  
    3636 * Returns a non-zero value if an error occurs.
    3737 **********************************************************************/
    38 int tr_netResolve( char * address, struct in_addr * addr )
     38int tr_netResolve( const char * address, struct in_addr * addr )
    3939{
    4040    addr->s_addr = inet_addr( address );
     
    5353struct tr_resolve_s
    5454{
    55     int            status;
     55    tr_tristate_t  status;
    5656    char           * address;
    5757    struct in_addr addr;
     
    9595 * Adds an address to the resolution queue.
    9696 **********************************************************************/
    97 tr_resolve_t * tr_netResolveInit( char * address )
     97tr_resolve_t * tr_netResolveInit( const char * address )
    9898{
    9999    tr_resolve_t * r;
    100100
    101101    r           = malloc( sizeof( tr_resolve_t ) );
    102     r->status   = TR_RESOLVE_WAIT;
     102    r->status   = TR_WAIT;
    103103    r->address  = strdup( address );
    104104    r->refcount = 2;
     
    126126 * Checks the current status of a resolution.
    127127 **********************************************************************/
    128 int tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
    129 {
    130     int ret;
     128tr_tristate_t tr_netResolvePulse( tr_resolve_t * r, struct in_addr * addr )
     129{
     130    tr_tristate_t ret;
    131131
    132132    tr_lockLock( &resolveLock );
    133133    ret = r->status;
    134     if( ret == TR_RESOLVE_OK )
     134    if( ret == TR_OK )
    135135    {
    136136        *addr = r->addr;
     
    202202        {
    203203            memcpy( &r->addr, host->h_addr, host->h_length );
    204             r->status = TR_RESOLVE_OK;
     204            r->status = TR_OK;
    205205        }
    206206        else
    207207        {
    208             r->status = TR_RESOLVE_ERROR;
     208            r->status = TR_ERROR;
    209209        }
    210210       
     
    252252}
    253253
    254 static int createSocket()
     254static int createSocket( int type )
    255255{
    256256    int s;
    257257
    258     s = socket( AF_INET, SOCK_STREAM, 0 );
     258    s = socket( AF_INET, type, 0 );
    259259    if( s < 0 )
    260260    {
     
    266266}
    267267
    268 int tr_netOpen( struct in_addr addr, in_port_t port )
     268int tr_netOpen( struct in_addr addr, in_port_t port, int type )
    269269{
    270270    int s;
    271271    struct sockaddr_in sock;
    272272
    273     s = createSocket();
     273    s = createSocket( type );
    274274    if( s < 0 )
    275275    {
     
    294294}
    295295
    296 int tr_netBind( int port )
     296#ifdef IP_ADD_MEMBERSHIP
     297int tr_netMcastOpen( int port, struct in_addr addr )
     298{
     299    int fd;
     300    struct ip_mreq req;
     301
     302    fd = tr_netBindUDP( port );
     303    if( 0 > fd )
     304    {
     305        return -1;
     306    }
     307
     308    memset( &req, 0, sizeof( req ) );
     309    req.imr_multiaddr.s_addr = addr.s_addr;
     310    req.imr_interface.s_addr = htonl( INADDR_ANY );
     311    if( setsockopt( fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &req, sizeof ( req ) ) )
     312    {
     313        tr_err( "Could not join multicast group (%s)", strerror( errno ) );
     314        tr_netClose( fd );
     315        return -1;
     316    }
     317
     318    return fd;
     319}
     320#else /* IP_ADD_MEMBERSHIP */
     321int tr_netMcastOpen( int port UNUSED, struct in_addr addr UNUSED )
     322{
     323    return -1;
     324}
     325#endif /* IP_ADD_MEMBERSHIP */
     326
     327int tr_netBind( int port, int type )
    297328{
    298329    int s;
    299330    struct sockaddr_in sock;
    300 #ifdef SO_REUSEADDR
     331#if defined( SO_REUSEADDR ) || defined( SO_REUSEPORT )
    301332    int optval;
    302333#endif
    303334
    304     s = createSocket();
     335    s = createSocket( type );
    305336    if( s < 0 )
    306337    {
     
    313344#endif
    314345
     346#ifdef SO_REUSEPORT
     347    if( SOCK_DGRAM == type )
     348    {
     349        optval = 1;
     350        setsockopt( s, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof( optval ) );
     351    }
     352#endif
     353
    315354    memset( &sock, 0, sizeof( sock ) );
    316355    sock.sin_family      = AF_INET;
     
    325364        return -1;
    326365    }
    327    
    328     tr_inf( "Binded port %d", port );
    329     listen( s, 5 );
    330366
    331367    return s;
     
    372408}
    373409
    374 int tr_netRecv( int s, uint8_t * buf, int size )
    375 {
    376     int ret;
    377 
    378     ret = recv( s, buf, size, 0 );
     410int tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * addr )
     411{
     412    socklen_t len;
     413    int       ret;
     414
     415    len = ( NULL == addr ? 0 : sizeof( *addr ) );
     416    ret = recvfrom( s, buf, size, 0, ( struct sockaddr * ) addr, &len );
    379417    if( ret < 0 )
    380418    {
  • trunk/libtransmission/net.h

    r791 r920  
    2727 * DNS resolution
    2828 **********************************************************************/
    29 int tr_netResolve( char *, struct in_addr * );
     29int tr_netResolve( const char *, struct in_addr * );
    3030
    31 #define TR_RESOLVE_WAIT  0
    32 #define TR_RESOLVE_ERROR 1
    33 #define TR_RESOLVE_OK    2
    3431typedef struct tr_resolve_s tr_resolve_t;
    3532void           tr_netResolveThreadInit();
    3633void           tr_netResolveThreadClose();
    37 tr_resolve_t * tr_netResolveInit( char * );
    38 int            tr_netResolvePulse( tr_resolve_t *, struct in_addr * );
     34tr_resolve_t * tr_netResolveInit( const char * );
     35tr_tristate_t  tr_netResolvePulse( tr_resolve_t *, struct in_addr * );
    3936void           tr_netResolveClose( tr_resolve_t * );
    4037
     
    4340 * TCP sockets
    4441 **********************************************************************/
    45 int  tr_netOpen    ( struct in_addr addr, in_port_t port );
    46 int  tr_netBind    ( int );
     42#define tr_netOpenTCP( addr, port ) tr_netOpen( (addr), (port), SOCK_STREAM )
     43#define tr_netOpenUDP( addr, port ) tr_netOpen( (addr), (port), SOCK_DGRAM )
     44int  tr_netOpen    ( struct in_addr addr, in_port_t port, int type );
     45int  tr_netMcastOpen( int port, struct in_addr addr );
     46#define tr_netBindTCP( port ) tr_netBind( (port), SOCK_STREAM )
     47#define tr_netBindUDP( port ) tr_netBind( (port), SOCK_DGRAM )
     48int  tr_netBind    ( int port, int type );
    4749int  tr_netAccept  ( int s, struct in_addr *, in_port_t * );
    4850void tr_netClose   ( int s );
     
    5153#define TR_NET_CLOSE 0x40000000
    5254int  tr_netSend    ( int s, uint8_t * buf, int size );
    53 int  tr_netRecv    ( int s, uint8_t * buf, int size );
     55#define tr_netRecv( s, buf, size ) tr_netRecvFrom( (s), (buf), (size), NULL )
     56int  tr_netRecvFrom( int s, uint8_t * buf, int size, struct sockaddr_in * );
    5457
    5558void tr_netNtop( const struct in_addr * addr, char * buf, int len );
  • trunk/libtransmission/peer.c

    r774 r920  
    101101
    102102#define peer_dbg( a... ) __peer_dbg( peer, ## a )
     103static void __peer_dbg( tr_peer_t * peer, char * msg, ... ) PRINTF( 2, 3 );
     104
    103105static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
    104106{
  • trunk/libtransmission/peerutils.h

    r261 r920  
    152152        !tr_fdSocketWillCreate( tor->fdlimit, 0 ) )
    153153    {
    154         peer->socket = tr_netOpen( peer->addr, peer->port );
     154        peer->socket = tr_netOpenTCP( peer->addr, peer->port );
    155155        if( peer->socket < 0 )
    156156        {
  • trunk/libtransmission/platform.c

    r679 r920  
    197197}
    198198
     199#if defined( BSD )
     200
     201#include <sys/sysctl.h>
     202#include <net/route.h>
     203
     204static uint8_t *
     205getroute( int * buflen );
     206static int
     207parseroutes( uint8_t * buf, int len, struct in_addr * addr );
     208
     209int
     210tr_getDefaultRoute( struct in_addr * addr )
     211{
     212    uint8_t * buf;
     213    int len;
     214
     215    buf = getroute( &len );
     216    if( NULL == buf )
     217    {
     218        tr_err( "failed to get default route (BSD)" );
     219        return 1;
     220    }
     221
     222    len = parseroutes( buf, len, addr );
     223    free( buf );
     224
     225    return len;
     226}
     227
     228#ifndef SA_SIZE
     229#define ROUNDUP( a, size ) \
     230    ( ( (a) & ( (size) - 1 ) ) ? ( 1 + ( (a) | ( (size) - 1 ) ) ) : (a) )
     231#define SA_SIZE( sap ) \
     232    ( sap->sa_len ? ROUNDUP( (sap)->sa_len, sizeof( u_long ) ) : \
     233                    sizeof( u_long ) )
     234#endif /* !SA_SIZE */
     235#define NEXT_SA( sap ) \
     236    (struct sockaddr *) ( (caddr_t) (sap) + ( SA_SIZE( (sap) ) ) )
     237
     238static uint8_t *
     239getroute( int * buflen )
     240{
     241    int     mib[6];
     242    size_t  len;
     243    uint8_t * buf;
     244
     245    mib[0] = CTL_NET;
     246    mib[1] = PF_ROUTE;
     247    mib[2] = 0;
     248    mib[3] = AF_INET;
     249    mib[4] = NET_RT_FLAGS;
     250    mib[5] = RTF_GATEWAY;
     251
     252    if( sysctl( mib, 6, NULL, &len, NULL, 0 ) )
     253    {
     254        if( ENOENT != errno )
     255        {
     256            tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     257                    strerror( errno ) );
     258        }
     259        *buflen = 0;
     260        return NULL;
     261    }
     262
     263    buf = malloc( len );
     264    if( NULL == buf )
     265    {
     266        *buflen = 0;
     267        return NULL;
     268    }
     269
     270    if( sysctl( mib, 6, buf, &len, NULL, 0 ) )
     271    {
     272        tr_err( "sysctl net.route.0.inet.flags.gateway failed (%s)",
     273                strerror( errno ) );
     274        free( buf );
     275        *buflen = 0;
     276        return NULL;
     277    }
     278
     279    *buflen = len;
     280
     281    return buf;
     282}
     283
     284static int
     285parseroutes( uint8_t * buf, int len, struct in_addr * addr )
     286{
     287    uint8_t            * end;
     288    struct rt_msghdr   * rtm;
     289    struct sockaddr    * sa;
     290    struct sockaddr_in * sin;
     291    int                  ii;
     292    struct in_addr       dest, gw;
     293
     294    end = buf + len;
     295    while( end > buf + sizeof( *rtm ) )
     296    {
     297        rtm = (struct rt_msghdr *) buf;
     298        buf += rtm->rtm_msglen;
     299        if( end >= buf )
     300        {
     301            dest.s_addr = INADDR_NONE;
     302            gw.s_addr   = INADDR_NONE;
     303            sa = (struct sockaddr *) ( rtm + 1 );
     304
     305            for( ii = 0; ii < RTAX_MAX && (uint8_t *) sa < buf; ii++ )
     306            {
     307                if( buf < (uint8_t *) NEXT_SA( sa ) )
     308                {
     309                    break;
     310                }
     311
     312                if( rtm->rtm_addrs & ( 1 << ii ) )
     313                {
     314                    if( AF_INET == sa->sa_family )
     315                    {
     316                        sin = (struct sockaddr_in *) sa;
     317                        switch( ii )
     318                        {
     319                            case RTAX_DST:
     320                                dest = sin->sin_addr;
     321                                break;
     322                            case RTAX_GATEWAY:
     323                                gw = sin->sin_addr;
     324                                break;
     325                        }
     326                    }
     327                    sa = NEXT_SA( sa );
     328                }
     329            }
     330
     331            if( INADDR_ANY == dest.s_addr && INADDR_NONE != gw.s_addr )
     332            {
     333                *addr = gw;
     334                return 0;
     335            }
     336        }
     337    }
     338
     339    return 1;
     340}
     341
     342#elif defined( linux ) || defined( __linux ) || defined( __linux__ )
     343
     344#include <linux/types.h>
     345#include <linux/netlink.h>
     346#include <linux/rtnetlink.h>
     347
     348#define SEQNUM 195909
     349
     350static int
     351getsock( void );
     352static uint8_t *
     353getroute( int fd, unsigned int * buflen );
     354static int
     355parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr );
     356
     357int
     358tr_getDefaultRoute( struct in_addr * addr )
     359{
     360    int fd, ret;
     361    unsigned int len;
     362    uint8_t * buf;
     363
     364    ret = 1;
     365    fd = getsock();
     366    if( 0 <= fd )
     367    {
     368        while( ret )
     369        {
     370            buf = getroute( fd, &len );
     371            if( NULL == buf )
     372            {
     373                break;
     374            }
     375            ret = parseroutes( buf, len, addr );
     376            free( buf );
     377        }
     378        close( fd );
     379    }
     380
     381    if( ret )
     382    {
     383        tr_err( "failed to get default route (Linux)" );
     384    }
     385
     386    return ret;
     387}
     388
     389static int
     390getsock( void )
     391{
     392    int fd, flags;
     393    struct
     394    {
     395        struct nlmsghdr nlh;
     396        struct rtgenmsg rtg;
     397    } req;
     398    struct sockaddr_nl snl;
     399
     400    fd = socket( PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE );
     401    if( 0 > fd )
     402    {
     403        tr_err( "failed to create routing socket (%s)", strerror( errno ) );
     404        return -1;
     405    }
     406
     407    flags = fcntl( fd, F_GETFL );
     408    if( 0 > flags || 0 > fcntl( fd, F_SETFL, O_NONBLOCK | flags ) )
     409    {
     410        tr_err( "failed to set socket nonblocking (%s)", strerror( errno ) );
     411        close( fd );
     412        return -1;
     413    }
     414
     415    bzero( &snl, sizeof( snl ) );
     416    snl.nl_family = AF_NETLINK;
     417
     418    bzero( &req, sizeof( req ) );
     419    req.nlh.nlmsg_len = NLMSG_LENGTH( sizeof( req.rtg ) );
     420    req.nlh.nlmsg_type = RTM_GETROUTE;
     421    req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
     422    req.nlh.nlmsg_seq = SEQNUM;
     423    req.nlh.nlmsg_pid = 0;
     424    req.rtg.rtgen_family = AF_INET;
     425
     426    if( 0 > sendto( fd, &req, sizeof( req ), 0,
     427                    (struct sockaddr *) &snl, sizeof( snl ) ) )
     428    {
     429        tr_err( "failed to write to routing socket (%s)", strerror( errno ) );
     430        close( fd );
     431        return -1;
     432    }
     433
     434    return fd;
     435}
     436
     437static uint8_t *
     438getroute( int fd, unsigned int * buflen )
     439{
     440    void             * buf;
     441    unsigned int       len;
     442    ssize_t            res;
     443    struct sockaddr_nl snl;
     444    socklen_t          slen;
     445
     446    len = 8192;
     447    buf = calloc( 1, len );
     448    if( NULL == buf )
     449    {
     450        *buflen = 0;
     451        return NULL;
     452    }
     453
     454    for( ;; )
     455    {
     456        bzero( &snl, sizeof( snl ) );
     457        slen = sizeof( snl );
     458        res = recvfrom( fd, buf, len, 0, (struct sockaddr *) &snl, &slen );
     459        if( 0 > res )
     460        {
     461            if( EAGAIN != errno )
     462            {
     463                tr_err( "failed to read from routing socket (%s)",
     464                        strerror( errno ) );
     465            }
     466            free( buf );
     467            *buflen = 0;
     468            return NULL;
     469        }
     470        if( slen < sizeof( snl ) || AF_NETLINK != snl.nl_family )
     471        {
     472            tr_err( "bad address" );
     473            free( buf );
     474            *buflen = 0;
     475            return NULL;
     476        }
     477
     478        if( 0 == snl.nl_pid )
     479        {
     480            break;
     481        }
     482    }
     483
     484    *buflen = res;
     485
     486    return buf;
     487}
     488
     489static int
     490parseroutes( uint8_t * buf, unsigned int len, struct in_addr * addr )
     491{
     492    struct nlmsghdr * nlm;
     493    struct nlmsgerr * nle;
     494    struct rtmsg    * rtm;
     495    struct rtattr   * rta;
     496    int               rtalen;
     497    struct in_addr    gw, dst;
     498
     499    nlm = ( struct nlmsghdr * ) buf;
     500    while( NLMSG_OK( nlm, len ) )
     501    {
     502        gw.s_addr = INADDR_ANY;
     503        dst.s_addr = INADDR_ANY;
     504        if( NLMSG_ERROR == nlm->nlmsg_type )
     505        {
     506            nle = (struct nlmsgerr *) NLMSG_DATA( nlm );
     507            if( NLMSG_LENGTH( NLMSG_ALIGN( sizeof( struct nlmsgerr ) ) ) >
     508                nlm->nlmsg_len )
     509            {
     510                tr_err( "truncated netlink error" );
     511            }
     512            else
     513            {
     514                tr_err( "netlink error (%s)", strerror( nle->error ) );
     515            }
     516            return 1;
     517        }
     518        else if( RTM_NEWROUTE == nlm->nlmsg_type && SEQNUM == nlm->nlmsg_seq &&
     519                 getpid() == (pid_t) nlm->nlmsg_pid &&
     520                 NLMSG_LENGTH( sizeof( struct rtmsg ) ) <= nlm->nlmsg_len )
     521        {
     522            rtm = NLMSG_DATA( nlm );
     523            rta = RTM_RTA( rtm );
     524            rtalen = RTM_PAYLOAD( nlm );
     525
     526            while( RTA_OK( rta, rtalen ) )
     527            {
     528                if( sizeof( struct in_addr ) <= RTA_PAYLOAD( rta ) )
     529                {
     530                    switch( rta->rta_type )
     531                    {
     532                        case RTA_GATEWAY:
     533                            memcpy( &gw, RTA_DATA( rta ), sizeof( gw ) );
     534                            break;
     535                        case RTA_DST:
     536                            memcpy( &dst, RTA_DATA( rta ), sizeof( dst ) );
     537                            break;
     538                    }
     539                }
     540                rta = RTA_NEXT( rta, rtalen );
     541            }
     542        }
     543
     544        if( INADDR_NONE != gw.s_addr && INADDR_ANY != gw.s_addr &&
     545            INADDR_ANY == dst.s_addr )
     546        {
     547            *addr = gw;
     548            return 0;
     549        }
     550
     551        nlm = NLMSG_NEXT( nlm, len );
     552    }
     553
     554    return 1;
     555}
     556
     557#else /* not BSD or Linux */
     558
     559int
     560tr_getDefaultRoute( struct in_addr * addr UNUSED )
     561{
     562    tr_inf( "don't know how to get default route on this platform" );
     563    return 1;
     564}
     565
     566#endif
  • trunk/libtransmission/platform.h

    r310 r920  
    6161}
    6262
     63int
     64tr_getDefaultRoute( struct in_addr * addr );
     65
    6366#endif
  • trunk/libtransmission/tracker.c

    r854 r920  
    4343    uint64_t       dateOk;
    4444
    45 #define TC_STATUS_IDLE    1
    46 #define TC_STATUS_RESOLVE 2
    47 #define TC_STATUS_CONNECT 4
    48 #define TC_STATUS_RECV    8
    49     char           status;
    50 
    5145#define TC_ATTEMPT_NOREACH 1
    5246#define TC_ATTEMPT_ERROR   2
     
    5448    char           lastAttempt;
    5549
    56     tr_resolve_t * resolve;
    57     int            socket;
    58     uint8_t      * buf;
    59     int            size;
    60     int            pos;
     50    tr_http_t    * http;
    6151
    6252    int            bindPort;
     
    6757};
    6858
    69 static void sendQuery  ( tr_tracker_t * tc );
    70 static void recvAnswer ( tr_tracker_t * tc );
     59static tr_http_t * getQuery   ( tr_tracker_t * tc );
     60static void        readAnswer ( tr_tracker_t * tc, const char *, int );
    7161
    7262tr_tracker_t * tr_trackerInit( tr_torrent_t * tor )
     
    8474    tc->leechers = -1;
    8575
    86     tc->status   = TC_STATUS_IDLE;
    8776    tc->lastAttempt = TC_ATTEMPT_NOREACH;
    88     tc->size     = 1024;
    89     tc->buf      = malloc( tc->size );
    9077
    9178    tc->bindPort = *(tor->bindPort);
     
    160147    tr_torrent_t * tor = tc->tor;
    161148    tr_info_t    * inf = &tor->info;
    162     uint64_t       now = tr_date();
    163 
    164     if( ( tc->status & TC_STATUS_IDLE ) && shouldConnect( tc ) )
    165     {
    166         tc->resolve = tr_netResolveInit( inf->trackerAddress );
     149    const char   * data;
     150    int            len;
     151
     152    if( ( NULL == tc->http ) && shouldConnect( tc ) )
     153    {
     154        if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
     155        {
     156            return 0;
     157        }
     158        tc->dateTry = tr_date();
     159        tc->http = getQuery( tc );
    167160
    168161        tr_inf( "Tracker: connecting to %s:%d (%s)",
     
    173166                    ( 0 < tc->newPort ? "sending 'stopped' to change port" :
    174167                      "getting peers" ) ) ) );
    175 
    176         tc->status  = TC_STATUS_RESOLVE;
    177         tc->dateTry = tr_date();
    178     }
    179 
    180     if( tc->status & TC_STATUS_RESOLVE )
    181     {
    182         int ret;
    183         struct in_addr addr;
    184 
    185         ret = tr_netResolvePulse( tc->resolve, &addr );
    186         if( ret == TR_RESOLVE_WAIT )
    187         {
    188             return 0;
    189         }
    190         else
    191         {
    192             tr_netResolveClose( tc->resolve );
    193         }
    194        
    195         if( ret == TR_RESOLVE_ERROR )
    196         {
    197             tc->status = TC_STATUS_IDLE;
    198             return 0;
    199         }
    200 
    201         if( tr_fdSocketWillCreate( tor->fdlimit, 1 ) )
    202         {
    203             tc->status = TC_STATUS_IDLE;
    204             return 0;
    205         }
    206 
    207         tc->socket = tr_netOpen( addr, htons( inf->trackerPort ) );
    208         if( tc->socket < 0 )
    209         {
    210             tr_fdSocketClosed( tor->fdlimit, 1 );
    211             tc->status = TC_STATUS_IDLE;
    212             return 0;
    213         }
    214 
    215         tc->status = TC_STATUS_CONNECT;
    216     }
    217 
    218     if( tc->status & TC_STATUS_CONNECT )
    219     {
    220         /* We are connecting to the tracker. Try to send the query */
    221         sendQuery( tc );
    222     }
    223 
    224     if( tc->status & TC_STATUS_RECV )
    225     {
    226         /* Try to get something */
    227         recvAnswer( tc );
    228     }
    229 
    230     if( tc->status > TC_STATUS_IDLE && now > tc->dateTry + 60000 )
    231     {
    232         /* Give up if the request wasn't successful within 60 seconds */
    233         tr_inf( "Tracker: timeout reached (60 s)" );
    234 
    235         tr_netClose( tc->socket );
    236         tr_fdSocketClosed( tor->fdlimit, 1 );
    237 
    238         tc->status  = TC_STATUS_IDLE;
    239         tc->dateTry = tr_date();
     168    }
     169
     170    if( NULL != tc->http )
     171    {
     172        switch( tr_httpPulse( tc->http, &data, &len ) )
     173        {
     174            case TR_WAIT:
     175                return 0;
     176
     177            case TR_ERROR:
     178                tr_httpClose( tc->http );
     179                tr_fdSocketClosed( tor->fdlimit, 1 );
     180                tc->http    = NULL;
     181                tc->dateTry = tr_date();
     182                return 0;
     183
     184            case TR_OK:
     185                readAnswer( tc, data, len );
     186                tr_httpClose( tc->http );
     187                tc->http = NULL;
     188                tr_fdSocketClosed( tor->fdlimit, 1 );
     189                break;
     190        }
    240191    }
    241192
     
    254205    tr_torrent_t * tor = tc->tor;
    255206
    256     if( tc->status > TC_STATUS_CONNECT )
     207    if( NULL != tc->http )
    257208    {
    258209        /* If we are already sendy a query at the moment, we need to
    259210           reconnect */
    260         tr_netClose( tc->socket );
     211        tr_httpClose( tc->http );
     212        tc->http = NULL;
    261213        tr_fdSocketClosed( tor->fdlimit, 1 );
    262         tc->status = TC_STATUS_IDLE;
    263214    }
    264215
     
    268219
    269220    /* Even if we have connected recently, reconnect right now */
    270     if( tc->status & TC_STATUS_IDLE )
    271     {
    272         tc->dateTry = 0;
    273     }
     221    tc->dateTry = 0;
    274222}
    275223
     
    278226    tr_torrent_t * tor = tc->tor;
    279227
    280     if( tc->status == TC_STATUS_RESOLVE )
    281     {
    282         tr_netResolveClose( tc->resolve );
    283     }
    284     else if( tc->status > TC_STATUS_RESOLVE )
    285     {
    286         tr_netClose( tc->socket );
     228    if( NULL != tc->http )
     229    {
     230        tr_httpClose( tc->http );
    287231        tr_fdSocketClosed( tor->fdlimit, 1 );
    288232    }
    289     free( tc->buf );
    290233    free( tc );
    291234}
    292235
    293 static void sendQuery( tr_tracker_t * tc )
     236static tr_http_t * getQuery( tr_tracker_t * tc )
    294237{
    295238    tr_torrent_t * tor = tc->tor;
    296239    tr_info_t    * inf = &tor->info;
    297240
    298     char     * event;
    299     uint64_t   left;
    300     int        ret;
    301     uint64_t   down;
    302     uint64_t   up;
     241    char         * event;
     242    uint64_t       left;
     243    uint64_t       down;
     244    uint64_t       up;
    303245
    304246    assert( tor->downloaded >= tc->download && tor->uploaded >= tc->upload );
     
    331273    left = tr_cpLeftBytes( tor->completion );
    332274
    333     ret = snprintf( (char *) tc->buf, tc->size,
    334             "GET %s?"
    335             "info_hash=%s&"
    336             "peer_id=%s&"
    337             "port=%d&"
    338             "uploaded=%"PRIu64"&"
    339             "downloaded=%"PRIu64"&"
    340             "left=%"PRIu64"&"
    341             "compact=1&"
    342             "numwant=50&"
    343             "key=%s"
    344             "%s "
    345             "HTTP/1.1\r\n"
    346             "Host: %s\r\n"
    347             "User-Agent: Transmission/%d.%d\r\n"
    348             "Connection: close\r\n\r\n",
    349             inf->trackerAnnounce, tor->hashString, tc->id,
    350             tc->bindPort, up, down,
    351             left, tor->key, event, inf->trackerAddress,
    352             VERSION_MAJOR, VERSION_MINOR );
    353 
    354     ret = tr_netSend( tc->socket, tc->buf, ret );
    355     if( ret & TR_NET_CLOSE )
    356     {
    357         tr_inf( "Tracker: connection failed" );
    358         tr_netClose( tc->socket );
    359         tr_fdSocketClosed( tor->fdlimit, 1 );
    360         tc->status  = TC_STATUS_IDLE;
    361         tc->dateTry = tr_date();
    362     }
    363     else if( !( ret & TR_NET_BLOCK ) )
    364     {
    365         // printf( "Tracker: sent %s", tc->buf );
    366         tc->status = TC_STATUS_RECV;
    367         tc->pos    = 0;
    368     }
    369 }
    370 
    371 static void recvAnswer( tr_tracker_t * tc )
     275    return tr_httpClient( TR_HTTP_GET, inf->trackerAddress,
     276                          inf->trackerPort,
     277                          "%s?"
     278                          "info_hash=%s&"
     279                          "peer_id=%s&"
     280                          "port=%d&"
     281                          "uploaded=%"PRIu64"&"
     282                          "downloaded=%"PRIu64"&"
     283                          "left=%"PRIu64"&"
     284                          "compact=1&"
     285                          "numwant=50&"
     286                          "key=%s"
     287                          "%s ",
     288                          inf->trackerAnnounce, tor->hashString, tc->id,
     289                          tc->bindPort, up, down, left, tor->key, event );
     290}
     291
     292static void readAnswer( tr_tracker_t * tc, const char * data, int len )
    372293{
    373294    tr_torrent_t * tor = tc->tor;
    374     int ret;
    375295    int i;
     296    int code;
    376297    benc_val_t   beAll;
    377298    benc_val_t * bePeers, * beFoo;
    378     uint8_t * body;
     299    const uint8_t * body;
    379300    int bodylen;
    380301    int shouldfree;
    381302
    382     if( tc->pos == tc->size )
    383     {
    384         tc->size *= 2;
    385         tc->buf   = realloc( tc->buf, tc->size );
    386     }
    387    
    388     ret = tr_netRecv( tc->socket, &tc->buf[tc->pos],
    389                     tc->size - tc->pos );
    390 
    391     if( ret & TR_NET_BLOCK )
    392     {
    393         return;
    394     }
    395     if( !( ret & TR_NET_CLOSE ) )
    396     {
    397         // printf( "got %d bytes\n", ret );
    398         tc->pos += ret;
    399         return;
    400     }
    401 
    402     tr_netClose( tc->socket );
    403     tr_fdSocketClosed( tor->fdlimit, 1 );
    404     // printf( "connection closed, got total %d bytes\n", tc->pos );
    405 
    406     tc->status  = TC_STATUS_IDLE;
    407303    tc->dateTry = tr_date();
    408 
    409     if( tc->pos < 12 || ( 0 != memcmp( tc->buf, "HTTP/1.0 ", 9 ) &&
    410                           0 != memcmp( tc->buf, "HTTP/1.1 ", 9 ) ) )
    411     {
    412         /* We don't have a complete HTTP status line */
    413         tr_inf( "Tracker: incomplete HTTP status line" );
     304    code = tr_httpResponseCode( data, len );
     305    if( 0 > code )
     306    {
     307        /* We don't have a valid HTTP status line */
     308        tr_inf( "Tracker: invalid HTTP status line" );
    414309        tc->lastAttempt = TC_ATTEMPT_NOREACH;
    415310        return;
    416311    }
    417312
    418     if( '2' != tc->buf[9] )
     313    if( !TR_HTTP_STATUS_OK( code ) )
    419314    {
    420315        /* we didn't get a 2xx status code */
    421         tr_err( "Tracker: invalid HTTP status code: %c%c%c",
    422                 tc->buf[9], tc->buf[10], tc->buf[11] );
     316        tr_err( "Tracker: invalid HTTP status code: %i", code );
    423317        tc->lastAttempt = TC_ATTEMPT_ERROR;
    424318        return;
     
    426320
    427321    /* find the end of the http headers */
    428     body = tr_memmem( tc->buf, tc->pos, "\015\012\015\012", 4 );
    429     if( NULL != body )
    430     {
    431         body += 4;
    432     }
    433     /* hooray for trackers that violate the HTTP spec */
    434     else if( NULL != ( body = tr_memmem( tc->buf, tc->pos, "\015\015", 2 ) ) ||
    435              NULL != ( body = tr_memmem( tc->buf, tc->pos, "\012\012", 2 ) ) )
    436     {
    437         body += 2;
    438     }
    439     else
     322    body = (uint8_t *) tr_httpParse( data, len, NULL );
     323    if( NULL == body )
    440324    {
    441325        tr_err( "Tracker: could not find end of HTTP headers" );
     
    443327        return;
    444328    }
    445     bodylen = tc->pos - (body - tc->buf);
     329    bodylen = len - (body - (const uint8_t*)data);
    446330
    447331    /* Find and load the dictionary */
     
    611495    tr_info_t * inf = &tor->info;
    612496
    613     int s, i, ret;
    614     uint8_t buf[1024];
    615     benc_val_t scrape, * val1, * val2;
    616     struct in_addr addr;
    617     uint64_t date;
    618     int pos, len;
    619     tr_resolve_t * resolve;
     497    tr_http_t  * http;
     498    const char * data, * body;
     499    int          datalen, bodylen;
     500    int          code, ii;
     501    benc_val_t   scrape, * val1, * val2;
    620502
    621503    if( !tor->scrape[0] )
     
    625507    }
    626508
    627     resolve = tr_netResolveInit( inf->trackerAddress );
    628     for( date = tr_date();; )
    629     {
    630         ret = tr_netResolvePulse( resolve, &addr );
    631         if( ret == TR_RESOLVE_OK )
    632         {
    633             tr_netResolveClose( resolve );
     509    http = tr_httpClient( TR_HTTP_GET, inf->trackerAddress, inf->trackerPort,
     510                          "%s?info_hash=%s", tor->scrape, tor->hashString );
     511
     512    data = NULL;
     513    while( NULL == data )
     514    {
     515        switch( tr_httpPulse( http, &data, &datalen ) )
     516        {
     517            case TR_WAIT:
     518                break;
     519
     520            case TR_ERROR:
     521                tr_httpClose( http );
     522                return 1;
     523
     524            case TR_OK:
     525                if( NULL == data || 0 >= datalen )
     526                {
     527                    tr_httpClose( http );
     528                    return 1;
     529                }
     530                break;
     531        }
     532        tr_wait( 10 );
     533    }
     534
     535    code = tr_httpResponseCode( data, datalen );
     536    if( !TR_HTTP_STATUS_OK( code ) )
     537    {
     538        tr_httpClose( http );
     539        return 1;
     540    }
     541
     542    body = tr_httpParse( data, datalen , NULL );
     543    if( NULL == body )
     544    {
     545        tr_httpClose( http );
     546        return 1;
     547    }
     548    bodylen = datalen - ( body - data );
     549
     550    for( ii = 0; ii < bodylen - 8; ii++ )
     551    {
     552        if( !memcmp( body + ii, "d5:files", 8 ) )
     553        {
    634554            break;
    635555        }
    636         if( ret == TR_RESOLVE_ERROR ||
    637             ( ret == TR_RESOLVE_WAIT && tr_date() > date + 10000 ) )
    638         {
    639             tr_err( "Could not resolve %s", inf->trackerAddress );
    640             tr_netResolveClose( resolve );
    641             return 1;
    642         }
    643         tr_wait( 10 );
    644     }
    645 
    646     s = tr_netOpen( addr, htons( inf->trackerPort ) );
    647     if( s < 0 )
    648     {
    649         return 1;
    650     }
    651 
    652     len = snprintf( (char *) buf, sizeof( buf ),
    653               "GET %s?info_hash=%s HTTP/1.1\r\n"
    654               "Host: %s\r\n"
    655               "Connection: close\r\n\r\n",
    656               tor->scrape, tor->hashString,
    657               inf->trackerAddress );
    658 
    659     for( date = tr_date();; )
    660     {
    661         ret = tr_netSend( s, buf, len );
    662         if( ret & TR_NET_CLOSE )
    663         {
    664             tr_err( "Could not connect to tracker" );
    665             tr_netClose( s );
    666             return 1;
    667         }
    668         else if( ret & TR_NET_BLOCK )
    669         {
    670             if( tr_date() > date + 10000 )
    671             {
    672                 tr_err( "Could not connect to tracker" );
    673                 tr_netClose( s );
    674                 return 1;
    675             }
    676         }
    677         else
    678         {
    679             break;
    680         }
    681         tr_wait( 10 );
    682     }
    683 
    684     pos = 0;
    685     for( date = tr_date();; )
    686     {
    687         ret = tr_netRecv( s, &buf[pos], sizeof( buf ) - pos );
    688         if( ret & TR_NET_CLOSE )
    689         {
    690             break;
    691         }
    692         else if( ret & TR_NET_BLOCK )
    693         {
    694             if( tr_date() > date + 10000 )
    695             {
    696                 tr_err( "Could not read from tracker" );
    697                 tr_netClose( s );
    698                 return 1;
    699             }
    700         }
    701         else
    702         {
    703             pos += ret;
    704         }
    705         tr_wait( 10 );
    706     }
    707 
    708     if( pos < 1 )
    709     {
    710         tr_err( "Could not read from tracker" );
    711         tr_netClose( s );
    712         return 1;
    713     }
    714 
    715     for( i = 0; i < pos - 8; i++ )
    716     {
    717         if( !memcmp( &buf[i], "d5:files", 8 ) )
    718         {
    719             break;
    720         }
    721     }
    722     if( i >= pos - 8 )
    723     {
    724         return 1;
    725     }
    726     if( tr_bencLoad( &buf[i], pos - i, &scrape, NULL ) )
    727     {
     556    }
     557    if( ii >= bodylen - 8 )
     558    {
     559        tr_httpClose( http );
     560        return 1;
     561    }
     562    if( tr_bencLoad( body + ii, bodylen - ii, &scrape, NULL ) )
     563    {
     564        tr_httpClose( http );
    728565        return 1;
    729566    }
     
    732569    if( !val1 )
    733570    {
     571        tr_bencFree( &scrape );
     572        tr_httpClose( http );
    734573        return 1;
    735574    }
     
    737576    if( !val1 )
    738577    {
     578        tr_bencFree( &scrape );
     579        tr_httpClose( http );
    739580        return 1;
    740581    }
     
    742583    if( !val2 )
    743584    {
     585        tr_bencFree( &scrape );
     586        tr_httpClose( http );
    744587        return 1;
    745588    }
     
    748591    if( !val2 )
    749592    {
     593        tr_bencFree( &scrape );
     594        tr_httpClose( http );
    750595        return 1;
    751596    }
    752597    *leechers = val2->val.i;
    753598    tr_bencFree( &scrape );
     599    tr_httpClose( http );
    754600
    755601    return 0;
  • trunk/libtransmission/transmission.c

    r815 r920  
    7575    h->fdlimit  = tr_fdInit();
    7676    h->choking  = tr_chokingInit( h );
     77    h->natpmp   = tr_natpmpInit( h->fdlimit );
     78    h->upnp     = tr_upnpInit( h->fdlimit );
    7779
    7880    h->bindPort = -1;
     
    105107    {
    106108        /* XXX should handle failure here in a better way */
    107         sock = tr_netBind( port );
     109        sock = tr_netBindTCP( port );
     110        if( 0 > sock)
     111        {
     112            tr_fdSocketClosed( h->fdlimit, 0 );
     113        }
     114        else
     115        {   
     116            tr_inf( "Bound listening port %d", port );
     117            listen( sock, 5 );
     118        }
    108119    }
    109120#else
     
    133144    h->bindSocket = sock;
    134145
     146    tr_natpmpForwardPort( h->natpmp, port );
     147    tr_upnpForwardPort( h->upnp, port );
     148
    135149    tr_lockUnlock( &h->acceptLock );
     150}
     151
     152void tr_natTraversalEnable( tr_handle_t * h )
     153{
     154    tr_natpmpStart( h->natpmp );
     155    tr_upnpStart( h->upnp );
     156}
     157
     158void tr_natTraversalDisable( tr_handle_t * h )
     159{
     160    tr_natpmpStop( h->natpmp );
     161    tr_upnpStop( h->upnp );
     162}
     163
     164int tr_natTraversalStatus( tr_handle_t * h )
     165{
     166    int statuses[] = {
     167        TR_NAT_TRAVERSAL_MAPPED,
     168        TR_NAT_TRAVERSAL_MAPPING,
     169        TR_NAT_TRAVERSAL_UNMAPPING,
     170        TR_NAT_TRAVERSAL_ERROR,
     171        TR_NAT_TRAVERSAL_NOTFOUND,
     172        TR_NAT_TRAVERSAL_DISABLED,
     173        -1,
     174    };
     175    int natpmp, upnp, ii;
     176
     177    natpmp = tr_natpmpStatus( h->natpmp );
     178    upnp = tr_upnpStatus( h->upnp );
     179
     180    for( ii = 0; 0 <= statuses[ii]; ii++ )
     181    {
     182        if( statuses[ii] == natpmp || statuses[ii] == upnp )
     183        {
     184            return statuses[ii];
     185        }
     186    }
     187
     188    assert( 0 );
     189
     190    return TR_NAT_TRAVERSAL_ERROR;
    136191}
    137192
     
    630685{
    631686    acceptStop( h );
     687    tr_natpmpClose( h->natpmp );
     688    tr_upnpClose( h->upnp );
    632689    tr_chokingClose( h->choking );
    633690    tr_fdClose( h->fdlimit );
     
    735792    {
    736793        date1 = tr_date();
     794
     795        /* do NAT-PMP and UPnP pulses here since there's nowhere better */
     796        tr_natpmpPulse( h->natpmp );
     797        tr_upnpPulse( h->upnp );
    737798
    738799        /* Check for incoming connections */
  • trunk/libtransmission/transmission.h

    r817 r920  
    100100 * tr_setBindPort
    101101 ***********************************************************************
    102  * Sets the port to listen for incoming peer connections
     102 * Sets the port to listen for incoming peer connections.
     103 * This can be safely called even with active torrents.
    103104 **********************************************************************/
    104105void tr_setBindPort( tr_handle_t *, int );
     106
     107/***********************************************************************
     108 * tr_natTraversalEnable
     109 * tr_natTraversalDisable
     110 ***********************************************************************
     111 * Enable or disable NAT traversal using NAT-PMP or UPnP IGD.
     112 **********************************************************************/
     113void tr_natTraversalEnable( tr_handle_t * );
     114void tr_natTraversalDisable( tr_handle_t * );
     115
     116/***********************************************************************
     117 * tr_natTraversalStatus
     118 ***********************************************************************
     119 * Return the status of NAT traversal
     120 **********************************************************************/
     121#define TR_NAT_TRAVERSAL_MAPPING        1
     122#define TR_NAT_TRAVERSAL_MAPPED         2
     123#define TR_NAT_TRAVERSAL_NOTFOUND       3
     124#define TR_NAT_TRAVERSAL_ERROR          4
     125#define TR_NAT_TRAVERSAL_UNMAPPING      5
     126#define TR_NAT_TRAVERSAL_DISABLED       6
     127#define TR_NAT_TRAVERSAL_IS_DISABLED( st ) \
     128  ( TR_NAT_TRAVERSAL_DISABLED == (st) || TR_NAT_TRAVERSAL_UNMAPPING == (st) )
     129int tr_natTraversalStatus( tr_handle_t * );
    105130
    106131/***********************************************************************
  • trunk/libtransmission/utils.c

    r837 r920  
    2525#include "transmission.h"
    2626
     27#define SPRINTF_BUFSIZE         100
     28
    2729static tr_lock_t      * messageLock = NULL;
    2830static int              messageLevel = 0;
     
    9799void tr_msg( int level, char * msg, ... )
    98100{
    99     va_list          args;
     101    va_list         args1, args2;
    100102    tr_msg_list_t * newmsg;
     103    int             len1, len2;
    101104
    102105    assert( NULL != messageLock );
     
    113116    if( messageLevel >= level )
    114117    {
    115         va_start( args, msg );
     118        va_start( args1, msg );
    116119        if( messageQueuing )
    117120        {
     
    121124                newmsg->level = level;
    122125                newmsg->when = time( NULL );
    123                 vasprintf( &newmsg->message, msg, args );
     126                len1 = len2 = 0;
     127                va_start( args2, msg );
     128                tr_vsprintf( &newmsg->message, &len1, &len2, msg,
     129                             args1, args2 );
     130                va_end( args2 );
    124131                if( NULL == newmsg->message )
    125132                {
     
    135142        else
    136143        {
    137             vfprintf( stderr, msg, args );
     144            vfprintf( stderr, msg, args1 );
    138145            fputc( '\n', stderr );
    139146        }
    140         va_end( args );
     147        va_end( args1 );
    141148    }
    142149
     
    235242    return 0;
    236243}
     244
     245#define UPPER( cc ) \
     246    ( 'a' <= (cc) && 'z' >= (cc) ? (cc) - ( 'a' - 'A' ) : (cc) )
     247
     248int tr_strncasecmp( const char * first, const char * second, int len )
     249{
     250    int ii;
     251    char firstchar, secondchar;
     252
     253    if( 0 > len )
     254    {
     255        len = strlen( first );
     256        ii = strlen( second );
     257        len = MIN( len, ii );
     258    }
     259
     260    for( ii = 0; ii < len; ii++ )
     261    {
     262        if( first[ii] != second[ii] )
     263        {
     264            firstchar = UPPER( first[ii] );
     265            secondchar = UPPER( second[ii] );
     266            if( firstchar > secondchar )
     267            {
     268                return 1;
     269            }
     270            else if( firstchar < secondchar )
     271            {
     272                return -1;
     273            }
     274        }
     275        if( '\0' == first[ii] )
     276        {
     277            /* if first[ii] is '\0' then second[ii] is too */
     278            return 0;
     279        }
     280    }
     281
     282    return 0;
     283}
     284
     285int tr_sprintf( char ** buf, int * used, int * max, const char * format, ... )
     286{
     287    va_list ap1, ap2;
     288    int     ret;
     289
     290    va_start( ap1, format );
     291    va_start( ap2, format );
     292    ret = tr_vsprintf( buf, used, max, format, ap1, ap2 );
     293    va_end( ap2 );
     294    va_end( ap1 );
     295
     296    return ret;
     297}
     298
     299int tr_vsprintf( char ** buf, int * used, int * max, const char * fmt,
     300                 va_list ap1, va_list ap2 )
     301{
     302    int     want;
     303    char  * newbuf;
     304
     305    want = vsnprintf( NULL, 0, fmt, ap1 );
     306
     307    while( *used + want + 1 > *max )
     308    {
     309        *max += SPRINTF_BUFSIZE;
     310        newbuf = realloc( *buf, *max );
     311        if( NULL == newbuf )
     312        {
     313            return 1;
     314        }
     315        *buf = newbuf;
     316    }
     317
     318    *used += vsnprintf( *buf + *used, *max - *used, fmt, ap2 );
     319
     320    return 0;
     321}
     322
     323char *
     324tr_dupstr( const char * base, int len )
     325{
     326    char * ret;
     327
     328    ret = malloc( len + 1 );
     329    if( NULL != ret )
     330    {
     331        memcpy( ret, base, len );
     332        ret[len] = '\0';
     333    }
     334
     335    return ret;
     336}
  • trunk/libtransmission/utils.h

    r815 r920  
    3131#define tr_inf( a... ) tr_msg( TR_MSG_INF, ## a )
    3232#define tr_dbg( a... ) tr_msg( TR_MSG_DBG, ## a )
    33 void tr_msg  ( int level, char * msg, ... );
     33void tr_msg  ( int level, char * msg, ... ) PRINTF( 2, 3 );
    3434
    3535int  tr_rand ( int );
     
    4444 **********************************************************************/
    4545int tr_mkdir( char * path );
     46
     47/***********************************************************************
     48 * tr_strcasecmp
     49 ***********************************************************************
     50 * A case-insensitive strncmp()
     51 **********************************************************************/
     52#define tr_strcasecmp( ff, ss ) ( tr_strncasecmp( (ff), (ss), -1 ) )
     53int tr_strncasecmp( const char * first, const char * second, int len );
     54
     55/***********************************************************************
     56 * tr_sprintf
     57 ***********************************************************************
     58 * Appends to the end of a buffer using printf formatting,
     59 * growing the buffer if needed
     60 **********************************************************************/
     61int tr_sprintf( char ** buf, int * used, int * max,
     62                const char * format, ... ) PRINTF( 4, 5 );
     63/* gee, it sure would be nice if BeOS had va_copy() */
     64int tr_vsprintf( char **, int *, int *, const char *, va_list, va_list );
     65
     66/***********************************************************************
     67 * tr_dupstr
     68 ***********************************************************************
     69 * Creates a nul-terminated string
     70 **********************************************************************/
     71char * tr_dupstr( const char * base, int len );
    4672
    4773/***********************************************************************
  • trunk/macosx/Controller.h

    r852 r920  
    3131#import "InfoWindowController.h"
    3232#import "MessageWindowController.h"
     33#import "PiecesWindowController.h"
    3334#import "Badger.h"
    3435#import "ImageBackgroundView.h"
     
    5051    InfoWindowController            * fInfoController;
    5152    MessageWindowController         * fMessageController;
     53    PiecesWindowController          * fPiecesWindowController;
    5254
    5355    IBOutlet NSWindow               * fWindow;
     
    106108- (void) resumeSelectedTorrents:    (id) sender;
    107109- (void) resumeAllTorrents:         (id) sender;
    108 - (void) resumeWaitingTorrents:     (id) sender;
    109110- (void) resumeTorrents:            (NSArray *) torrents;
     111
     112- (void) resumeSelectedTorrentsNoWait:  (id) sender;
     113- (void) resumeWaitingTorrents:         (id) sender;
     114- (void) resumeTorrentsNoWait:          (NSArray *) torrents;
    110115
    111116- (void) stopSelectedTorrents:      (id) sender;
     
    137142
    138143- (void) showMessageWindow: (id) sender;
     144- (void) showPiecesView: (id) sender;
    139145
    140146- (void) updateControlTint: (NSNotification *) notification;
     
    173179- (void) attemptToStartMultipleAuto: (NSArray *) torrents;
    174180
    175 - (void) reloadInspectorSettings: (NSNotification *) notification;
    176 
    177181- (void) checkAutoImportDirectory;
    178182
  • trunk/macosx/Controller.m

    r855 r920  
    8787        fMessageController = [[MessageWindowController alloc] initWithWindowNibName: @"MessageWindow"];
    8888        fInfoController = [[InfoWindowController alloc] initWithWindowNibName: @"InfoWindow"];
     89        fPiecesWindowController = [[PiecesWindowController alloc] initWithWindowNibName: @"PiecesWindow"];
    8990        fPrefsController = [[PrefsController alloc] initWithWindowNibName: @"PrefsWindow" handle: fLib];
    9091       
     
    101102{
    102103    [[NSNotificationCenter defaultCenter] removeObserver: self];
    103 
     104   
     105    [fInfoController release];
     106    [fMessageController release];
     107    [fPiecesWindowController release];
     108    [fPrefsController release];
     109   
     110    [fToolbar release];
    104111    [fTorrents release];
    105112    [fDisplayedTorrents release];
    106    
    107     [fToolbar release];
    108     [fInfoController release];
    109     [fPrefsController release];
    110113    [fBadger release];
    111114   
     
    333336    [nc addObserver: self selector: @selector(globalStartSettingChange:)
    334337                    name: @"GlobalStartSettingChange" object: nil];
    335 
    336     //check if torrent should now start
    337     [nc addObserver: self selector: @selector(torrentStartSettingChange:)
    338                     name: @"TorrentStartSettingChange" object: nil];
    339338   
    340339    //check if torrent should now start
    341340    [nc addObserver: self selector: @selector(torrentStoppedForRatio:)
    342341                    name: @"TorrentStoppedForRatio" object: nil];
    343    
    344     //change that just impacts the inspector
    345     [nc addObserver: self selector: @selector(reloadInspectorSettings:)
    346                     name: @"TorrentSettingChange" object: nil];
    347342   
    348343    //change that just impacts the dock badge
     
    364359    if ([fDefaults boolForKey: @"InfoVisible"])
    365360        [self showInfo: nil];
     361   
     362    if ([fDefaults boolForKey: @"PiecesViewerVisible"])
     363        [self showPiecesView: nil];
    366364   
    367365    //timer to auto toggle speed limit
     
    426424    [fTorrents makeObjectsPerformSelector: @selector(stopTransferForQuit)];
    427425   
     426    //disable NAT traversal
     427    tr_natTraversalDisable(fLib);
     428   
    428429    //remember window states and close all windows
    429430    [fDefaults setBool: [[fInfoController window] isVisible] forKey: @"InfoVisible"];
     431    [fDefaults setBool: [[fPiecesWindowController window] isVisible] forKey: @"PiecesViewerVisible"];
    430432    [[NSApp windows] makeObjectsPerformSelector: @selector(close)];
    431433    [self showStatusBar: NO animate: NO];
     
    439441        return;
    440442
    441     //wait for running transfers to stop (5 second timeout)
     443    //wait for running transfers to stop (5 second timeout) and for NAT to be disabled
    442444    NSDate * start = [NSDate date];
    443445    BOOL timeUp = NO;
     
    445447    NSEnumerator * enumerator = [fTorrents objectEnumerator];
    446448    Torrent * torrent;
    447     while (!timeUp && (torrent = [enumerator nextObject]))
     449    while (!timeUp && ((torrent = [enumerator nextObject]) || tr_natTraversalStatus(fLib) != TR_NAT_TRAVERSAL_DISABLED))
    448450        while (![torrent isPaused] && !(timeUp = [start timeIntervalSinceNow] < -5.0))
    449451        {
     
    544546    [panel setMessage: [NSString stringWithFormat: @"Select the download folder for \"%@\"", [torrent name]]];
    545547   
    546     NSDictionary * dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
    547                                     torrent, @"Torrent", files, @"Files", nil];
     548    NSDictionary * dictionary = [[NSDictionary alloc] initWithObjectsAndKeys: torrent, @"Torrent", files, @"Files", nil];
    548549
    549550    [panel beginSheetForDirectory: nil file: nil types: nil modalForWindow: fWindow modalDelegate: self
     
    625626{
    626627    [self resumeTorrents: fTorrents];
     628}
     629
     630- (void) resumeTorrents: (NSArray *) torrents
     631{
     632    NSEnumerator * enumerator = [torrents objectEnumerator];
     633    Torrent * torrent;
     634    while ((torrent = [enumerator nextObject]))
     635        [torrent setWaitToStart: YES];
     636   
     637    [self attemptToStartMultipleAuto: torrents];
     638   
     639    [self updateUI: nil];
     640    [self applyFilter: nil];
     641    [self updateTorrentHistory];
     642}
     643
     644- (void) resumeSelectedTorrentsNoWait:  (id) sender
     645{
     646    [self resumeTorrentsNoWait: [self torrentsAtIndexes: [fTableView selectedRowIndexes]]];
    627647}
    628648
     
    637657            [torrents addObject: torrent];
    638658   
    639     [self resumeTorrents: torrents];
    640 }
    641 
    642 - (void) resumeTorrents: (NSArray *) torrents
     659    [self resumeTorrentsNoWait: torrents];
     660}
     661
     662- (void) resumeTorrentsNoWait: (NSArray *) torrents
    643663{
    644664    [torrents makeObjectsPerformSelector: @selector(startTransfer)];
     
    646666    [self updateUI: nil];
    647667    [self applyFilter: nil];
    648     [fInfoController updateInfoStatsAndSettings];
    649668    [self updateTorrentHistory];
    650669}
     
    672691    [self updateUI: nil];
    673692    [self applyFilter: nil];
    674     [fInfoController updateInfoStatsAndSettings];
    675693    [self updateTorrentHistory];
    676694}
     
    919937}
    920938
     939- (void) showPiecesView: (id) sender
     940{
     941    if ([[fPiecesWindowController window] isVisible])
     942        [fPiecesWindowController close];
     943    else
     944    {
     945        [fPiecesWindowController updateView: NO];
     946        [[fPiecesWindowController window] orderFront: nil];
     947    }
     948}
     949
    921950- (void) updateControlTint: (NSNotification *) notification
    922951{
     
    948977    if ([[fInfoController window] isVisible])
    949978        [fInfoController updateInfoStats];
     979   
     980    //update pieces viewer
     981    if ([[fPiecesWindowController window] isVisible])
     982        [fPiecesWindowController updateView: NO];
    950983
    951984    //badge dock
     
    13881421    [self updateUI: nil];
    13891422    [self applyFilter: nil];
    1390     [fInfoController updateInfoStatsAndSettings];
    13911423    [self updateTorrentHistory];
    13921424}
     
    13951427{
    13961428    //don't try to start a transfer if there should be none waiting
    1397     if (![[fDefaults stringForKey: @"StartSetting"] isEqualToString: @"Wait"])
     1429    if (![fDefaults boolForKey: @"Queue"])
    13981430        return;
    13991431
    1400     int desiredActive = [fDefaults integerForKey: @"WaitToStartNumber"];
     1432    int desiredActive = [fDefaults integerForKey: @"QueueDownloadNumber"];
    14011433   
    14021434    NSEnumerator * enumerator = [fTorrents objectEnumerator];
     
    14331465        [self updateUI: nil];
    14341466        [self applyFilter: nil];
    1435         [fInfoController updateInfoStatsAndSettings];
    14361467        [self updateTorrentHistory];
    14371468    }
     
    14441475    [self updateUI: nil];
    14451476    [self applyFilter: nil];
    1446     [fInfoController updateInfoStatsAndSettings];
    14471477    [self updateTorrentHistory];
    14481478}
     
    14541484    [self updateUI: nil];
    14551485    [self applyFilter: nil];
    1456     [fInfoController updateInfoStatsAndSettings];
    14571486    [self updateTorrentHistory];
    14581487}
     
    14611490{
    14621491    [self applyFilter: nil];
    1463     [fInfoController updateInfoStatsAndSettings];
     1492    [fInfoController updateInfoStats];
     1493    [fInfoController updateInfoSettings];
    14641494   
    14651495    if ([fDefaults boolForKey: @"PlaySeedingSound"])
     
    14821512- (void) attemptToStartMultipleAuto: (NSArray *) torrents
    14831513{
    1484     NSString * startSetting = [fDefaults stringForKey: @"StartSetting"];
    1485     if ([startSetting isEqualToString: @"Start"])
     1514    if (![fDefaults boolForKey: @"Queue"])
    14861515    {
    14871516        NSEnumerator * enumerator = [torrents objectEnumerator];
     
    14931522        return;
    14941523    }
    1495     else if (![startSetting isEqualToString: @"Wait"])
    1496         return;
    1497     else;
    14981524   
    14991525    //determine the number of downloads needed to start
    1500     int desiredActive = [fDefaults integerForKey: @"WaitToStartNumber"];
     1526    int desiredActive = [fDefaults integerForKey: @"QueueDownloadNumber"];
    15011527           
    15021528    NSEnumerator * enumerator = [fTorrents objectEnumerator];
     
    15441570}
    15451571
    1546 - (void) reloadInspectorSettings: (NSNotification *) notification
    1547 {
    1548     [fInfoController updateInfoStatsAndSettings];
    1549 }
    1550 
    15511572-(void) watcher: (id<UKFileWatcher>) watcher receivedNotification: (NSString *) notification forPath: (NSString *) path
    15521573{
     
    15871608}
    15881609
    1589 /*- (void) tableView: (NSTableView *) t willDisplayCell: (id) cell
    1590     forTableColumn: (NSTableColumn *) tableColumn row: (int) row
    1591 {
    1592     [cell setTorrent: [fDisplayedTorrents objectAtIndex: row]];
    1593 }*/
    1594 
    15951610- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (int) row
    15961611{
     
    17131728- (void) tableViewSelectionDidChange: (NSNotification *) notification
    17141729{
    1715     [fInfoController updateInfoForTorrents: [self torrentsAtIndexes: [fTableView selectedRowIndexes]]];
     1730    NSArray * torrents = [self torrentsAtIndexes: [fTableView selectedRowIndexes]];
     1731    [fInfoController updateInfoForTorrents: torrents];
     1732   
     1733    Torrent * torrent = [torrents count] == 1 ? [torrents objectAtIndex: 0] : nil;
     1734    [fPiecesWindowController setTorrent: torrent];
    17161735}
    17171736
     
    19822001        NSEnumerator * enumerator = [fTorrents objectEnumerator];
    19832002        while ((torrent = [enumerator nextObject]))
    1984             if ([torrent isActive])
     2003            if ([torrent isActive] || [torrent waitingToStart])
    19852004                return YES;
    19862005        return NO;
     
    19932012        NSEnumerator * enumerator = [fTorrents objectEnumerator];
    19942013        while ((torrent = [enumerator nextObject]))
    1995             if ([torrent isPaused])
     2014            if ([torrent isPaused] && ![torrent waitingToStart])
    19962015                return YES;
    19972016        return NO;
     
    20062025       
    20072026        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
    2008             if ([[fDisplayedTorrents objectAtIndex: i] isActive])
     2027        {
     2028            torrent = [fDisplayedTorrents objectAtIndex: i];
     2029            if ([torrent isActive] || [torrent waitingToStart])
    20092030                return YES;
     2031        }
    20102032        return NO;
    20112033    }
     
    20142036    if ([ident isEqualToString: TOOLBAR_RESUME_SELECTED])
    20152037    {
     2038        Torrent * torrent;
    20162039        NSIndexSet * indexSet = [fTableView selectedRowIndexes];
    20172040        unsigned int i;
    20182041       
    20192042        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
    2020             if ([[fDisplayedTorrents objectAtIndex: i] isPaused])
     2043        {
     2044            torrent = [fDisplayedTorrents objectAtIndex: i];
     2045            if ([torrent isPaused] && ![torrent waitingToStart])
    20212046                return YES;
     2047        }
    20222048        return NO;
    20232049    }
     
    20452071    {
    20462072        NSString * title = [[fInfoController window] isVisible] ? @"Hide Inspector" : @"Show Inspector";
     2073        if (![[menuItem title] isEqualToString: title])
     2074                [menuItem setTitle: title];
     2075
     2076        return YES;
     2077    }
     2078   
     2079    //enable show pieces window
     2080    if (action == @selector(showPiecesView:))
     2081    {
     2082        NSString * title = [[fPiecesWindowController window] isVisible] ? @"Hide Pieces Viewer" : @"Show Pieces Viewer";
    20472083        if (![[menuItem title] isEqualToString: title])
    20482084                [menuItem setTitle: title];
     
    21332169        NSEnumerator * enumerator = [fTorrents objectEnumerator];
    21342170        while ((torrent = [enumerator nextObject]))
    2135             if ([torrent isActive])
     2171            if ([torrent isActive] || [torrent waitingToStart])
    21362172                return YES;
    21372173        return NO;
     
    21442180        NSEnumerator * enumerator = [fTorrents objectEnumerator];
    21452181        while ((torrent = [enumerator nextObject]))
    2146             if ([torrent isPaused])
     2182            if ([torrent isPaused] && ![torrent waitingToStart])
    21472183                return YES;
    21482184        return NO;
    21492185    }
    21502186   
    2151     //enable resume waiting item
     2187    //enable resume all waiting item
    21522188    if (action == @selector(resumeWaitingTorrents:))
    21532189    {
    2154         if (![[fDefaults stringForKey: @"StartSetting"] isEqualToString: @"Wait"])
     2190        if (![fDefaults boolForKey: @"Queue"])
    21552191            return NO;
    21562192   
     
    21622198        return NO;
    21632199    }
    2164 
    2165     //enable pause item
    2166     if (action == @selector(stopSelectedTorrents:))
    2167     {
    2168         if (!canUseTable)
    2169             return NO;
    2170    
    2171         Torrent * torrent;
    2172         NSIndexSet * indexSet = [fTableView selectedRowIndexes];
    2173         unsigned int i;
    2174        
    2175         for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
    2176         {
    2177             torrent = [fDisplayedTorrents objectAtIndex: i];
    2178             if ([torrent isActive])
    2179                 return YES;
    2180         }
    2181         return NO;
    2182     }
    2183    
    2184     //enable resume item
    2185     if (action == @selector(resumeSelectedTorrents:))
    2186     {
    2187         if (!canUseTable)
     2200   
     2201    //enable resume selected waiting item
     2202    if (action == @selector(resumeSelectedTorrentsNoWait:))
     2203    {
     2204        if (![fDefaults boolForKey: @"Queue"])
    21882205            return NO;
    21892206   
     
    21962213            torrent = [fDisplayedTorrents objectAtIndex: i];
    21972214            if ([torrent isPaused])
     2215                return YES;
     2216        }
     2217        return NO;
     2218    }
     2219
     2220    //enable pause item
     2221    if (action == @selector(stopSelectedTorrents:))
     2222    {
     2223        if (!canUseTable)
     2224            return NO;
     2225   
     2226        Torrent * torrent;
     2227        NSIndexSet * indexSet = [fTableView selectedRowIndexes];
     2228        unsigned int i;
     2229       
     2230        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
     2231        {
     2232            torrent = [fDisplayedTorrents objectAtIndex: i];
     2233            if ([torrent isActive] || [torrent waitingToStart])
     2234                return YES;
     2235        }
     2236        return NO;
     2237    }
     2238   
     2239    //enable resume item
     2240    if (action == @selector(resumeSelectedTorrents:))
     2241    {
     2242        if (!canUseTable)
     2243            return NO;
     2244   
     2245        Torrent * torrent;
     2246        NSIndexSet * indexSet = [fTableView selectedRowIndexes];
     2247        unsigned int i;
     2248       
     2249        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
     2250        {
     2251            torrent = [fDisplayedTorrents objectAtIndex: i];
     2252            if ([torrent isPaused] && ![torrent waitingToStart])
    21982253                return YES;
    21992254        }
  • trunk/macosx/Defaults.plist

    r807 r920  
    5353        <key>MoveFolder</key>
    5454        <string>~/Desktop</string>
     55        <key>NatTraversal</key>
     56        <true/>
     57        <key>PiecesViewerVisible</key>
     58        <false/>
    5559        <key>PlayDownloadSound</key>
    5660        <true/>
    5761        <key>PlaySeedingSound</key>
    5862        <false/>
     63        <key>Queue</key>
     64        <false/>
     65        <key>QueueDownloadNumber</key>
     66        <integer>3</integer>
    5967        <key>RatioCheck</key>
    6068        <false/>
     
    8795        <key>SpeedLimitUploadLimit</key>
    8896        <integer>10</integer>
    89         <key>StartSetting</key>
    90         <string>Start</string>
     97        <key>StartAtOpen</key>
     98        <true/>
    9199        <key>StatusBar</key>
    92100        <true/>
     
    97105        <key>UseAdvancedBar</key>
    98106        <false/>
    99         <key>WaitToStartNumber</key>
    100         <integer>3</integer>
    101107</dict>
    102108</plist>
  • trunk/macosx/English.lproj/InfoWindow.nib/classes.nib

    r797 r920  
    99        {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
    1010        {
    11             ACTIONS = {
    12                 revealFile = id;
    13                 setRatioCheck = id;
    14                 setRatioLimit = id;
    15                 setWaitToStart = id;
    16             };
     11            ACTIONS = {revealFile = id; setRatioCheck = id; setRatioLimit = id; };
    1712            CLASS = InfoWindowController;
    1813            LANGUAGE = ObjC;
     
    4742                fUploadedTotalField = NSTextField;
    4843                fUploadingToField = NSTextField;
    49                 fWaitToStartButton = NSButton;
    5044            };
    5145            SUPERCLASS = NSWindowController;
  • trunk/macosx/English.lproj/MainMenu.nib/classes.nib

    r852 r920  
    1616                resumeAllTorrents = id;
    1717                resumeSelectedTorrents = id;
     18                resumeSelectedTorrentsNoWait = id;
    1819                resumeWaitingTorrents = id;
    1920                revealFile = id;
     
    2829                showMainWindow = id;
    2930                showMessageWindow = id;
     31                showPiecesView = id;
    3032                showPreferenceWindow = id;
    3133                stopAllTorrents = id;
  • trunk/macosx/English.lproj/MainMenu.nib/info.nib

    r852 r920  
    88        <dict>
    99                <key>1041</key>
    10                 <string>439 418 208 130 0 0 1152 842 </string>
     10                <string>379 362 208 130 0 0 1024 746 </string>
    1111                <key>1480</key>
    1212                <string>366 546 420 63 0 0 1152 842 </string>
     
    1414                <string>337 545 477 67 0 0 1152 842 </string>
    1515                <key>29</key>
    16                 <string>104 684 451 44 0 0 1152 842 </string>
     16                <string>280 699 451 44 0 0 1152 842 </string>
    1717                <key>456</key>
    18                 <string>396 374 216 206 0 0 1152 842 </string>
     18                <string>340 316 240 225 0 0 1024 746 </string>
    1919                <key>581</key>
    2020                <string>571 464 115 99 0 0 1152 842 </string>
     
    3232        <key>IBOpenObjects</key>
    3333        <array>
     34                <integer>29</integer>
    3435                <integer>21</integer>
    35                 <integer>29</integer>
    3636        </array>
    3737        <key>IBSystem Version</key>
  • trunk/macosx/English.lproj/PrefsWindow.nib/classes.nib

    r752 r920  
    1818                setLimitCheck = id;
    1919                setMoveTorrent = id;
     20                setNat = id;
    2021                setPlaySound = id;
    2122                setPort = id;
     23                setQueueNumber = id;
    2224                setRatio = id;
    2325                setRatioCheck = id;
     
    2527                setSound = id;
    2628                setSpeedLimit = id;
    27                 setStartNumber = id;
    28                 setStartSetting = id;
     29                setStartAtOpen = id;
    2930                setUpdate = id;
     31                setUseQueue = id;
    3032            };
    3133            CLASS = PrefsController;
     
    4547                fGeneralView = NSView;
    4648                fImportFolderPopUp = NSPopUpButton;
     49                fNatCheck = NSButton;
     50                fNatStatusField = NSTextField;
     51                fNatStatusImage = NSImageView;
    4752                fNetworkView = NSView;
    4853                fPlayDownloadSoundCheck = NSButton;
    4954                fPlaySeedingSoundCheck = NSButton;
    5055                fPortField = NSTextField;
     56                fQueueCheck = NSButton;
     57                fQueueNumberField = NSTextField;
    5158                fQuitCheck = NSButton;
    5259                fQuitDownloadingCheck = NSButton;
     
    6168                fSpeedLimitDownloadField = NSTextField;
    6269                fSpeedLimitUploadField = NSTextField;
    63                 fStartMatrix = NSMatrix;
    64                 fStartNumberField = NSTextField;
     70                fStartAtOpenCheck = NSButton;
    6571                fTransfersView = NSView;
    6672                fUpdatePopUp = NSPopUpButton;
  • trunk/macosx/English.lproj/PrefsWindow.nib/info.nib

    r753 r920  
    44<dict>
    55        <key>IBDocumentLocation</key>
    6         <string>49 68 356 240 0 0 1152 842 </string>
     6        <string>15 73 356 240 0 0 1024 746 </string>
    77        <key>IBEditorPositions</key>
    88        <dict>
    99                <key>153</key>
    10                 <string>285 423 582 311 0 0 1152 842 </string>
     10                <string>30 315 577 267 0 0 1024 746 </string>
    1111                <key>28</key>
    12                 <string>58 372 582 290 0 0 1152 842 </string>
     12                <string>22 331 577 290 0 0 1024 746 </string>
    1313                <key>41</key>
    14                 <string>285 427 582 304 0 0 1152 842 </string>
     14                <string>230 355 563 317 0 0 1024 746 </string>
    1515                <key>66</key>
    16                 <string>164 527 582 104 0 0 1152 842 </string>
     16                <string>29 426 563 159 0 0 1024 746 </string>
    1717        </dict>
    1818        <key>IBFramework Version</key>
     
    2424        <key>IBOpenObjects</key>
    2525        <array>
    26                 <integer>153</integer>
     26                <integer>41</integer>
    2727        </array>
    2828        <key>IBSystem Version</key>
  • trunk/macosx/InfoWindowController.h

    r797 r920  
    5353    IBOutlet NSMatrix * fRatioMatrix;
    5454    IBOutlet NSTextField * fRatioLimitField;
    55     IBOutlet NSButton * fWaitToStartButton;
    5655}
    5756
    5857- (void) updateInfoForTorrents: (NSArray *) torrents;
    5958- (void) updateInfoStats;
    60 - (void) updateInfoStatsAndSettings;
     59- (void) updateInfoSettings;
    6160
    6261- (void) setNextTab;
     
    6766- (void) setRatioLimit: (id) sender;
    6867
    69 - (void) setWaitToStart: (id) sender;
    70 
    7168@end
  • trunk/macosx/InfoWindowController.m

    r842 r920  
    4444#define TAB_PEERS_HEIGHT 255.0
    4545#define TAB_FILES_HEIGHT 255.0
    46 #define TAB_OPTIONS_HEIGHT 116.0
     46#define TAB_OPTIONS_HEIGHT 83.0
    4747
    4848@interface InfoWindowController (Private)
     
    210210   
    211211    //update stats and settings
    212     [self updateInfoStatsAndSettings];
     212    [self updateInfoStats];
     213    [self updateInfoSettings];
    213214
    214215    //set file table
     
    283284}
    284285
    285 - (void) updateInfoStatsAndSettings
     286- (void) updateInfoSettings
    286287{
    287288    int numberSelected = [fTorrents count];
    288 
    289     //set wait to start
    290     BOOL waiting = NO, notWaiting = NO, canEnableWaiting = numberSelected > 0,
    291         waitingSettingOn = [[[NSUserDefaults standardUserDefaults] stringForKey: @"StartSetting"]
    292                                 isEqualToString: @"Wait"];
    293    
    294     NSEnumerator * enumerator = [fTorrents objectEnumerator];
    295     Torrent * torrent;
    296     while ((torrent = [enumerator nextObject]))
    297     {
    298         if ([torrent waitingToStart])
    299             waiting = YES;
    300         else
    301             notWaiting = YES;
    302        
    303         if (canEnableWaiting && !(![torrent isActive] && [torrent progress] < 1.0 && waitingSettingOn))
    304             canEnableWaiting = NO;
    305     }
    306    
    307     [fWaitToStartButton setState: waiting && notWaiting ? NSMixedState : (waiting ? NSOnState : NSOffState)];
    308     [fWaitToStartButton setEnabled: canEnableWaiting];
    309289
    310290    //set ratio settings
    311291    if (numberSelected > 0)
    312292    {
    313         enumerator = [fTorrents objectEnumerator];
    314         torrent = [enumerator nextObject]; //first torrent
     293        NSEnumerator * enumerator = [fTorrents objectEnumerator];
     294        Torrent * torrent = [enumerator nextObject]; //first torrent
    315295        const int INVALID = -99;
    316296        int ratioSetting = [torrent stopRatioSetting];
     
    593573}
    594574
    595 - (void) setWaitToStart: (id) sender
    596 {
    597     int state = [sender state];
    598 
    599     NSEnumerator * enumerator = [fTorrents objectEnumerator];
    600     Torrent * torrent;
    601     while ((torrent = [enumerator nextObject]))
    602         [torrent setWaitToStart: state];
    603    
    604     [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentStartSettingChange" object: fTorrents];
    605 }
    606 
    607575@end
  • trunk/macosx/MessageWindowController.m

    r844 r920  
    3131
    3232#define UPDATE_SECONDS  0.6
    33 #define MAX_LINES       1000
     33#define MAX_LINES       2500
    3434
    3535@interface MessageWindowController (Private)
  • trunk/macosx/PrefsController.h

    r752 r920  
    5151                            * fSpeedLimitAutoCheck;
    5252
    53     IBOutlet NSTextField    * fPortField;
     53    IBOutlet NSTextField    * fPortField, * fNatStatusField;
     54    IBOutlet NSButton       * fNatCheck;
     55    IBOutlet NSImageView    * fNatStatusImage;
     56    NSTimer                 * fNatStatusTimer;
     57    int                     fNatStatus;
    5458   
    5559    IBOutlet NSButton       * fRatioCheck;
    5660    IBOutlet NSTextField    * fRatioField;
    5761   
    58     IBOutlet NSMatrix       * fStartMatrix;
    59     IBOutlet NSTextField    * fStartNumberField;
     62    IBOutlet NSButton       * fQueueCheck, * fStartAtOpenCheck;
     63    IBOutlet NSTextField    * fQueueNumberField;
    6064   
    6165    IBOutlet SUUpdater      * fUpdater;
     
    7478- (void) checkUpdate;
    7579
    76 - (void) setStartSetting:   (id) sender;
    77 - (void) setStartNumber:    (id) sender;
     80- (void) setStartAtOpen:    (id) sender;
     81
     82- (void) setUseQueue:       (id) sender;
     83- (void) setQueueNumber:    (id) sender;
    7884
    7985- (void) setMoveTorrent:        (id) sender;
     
    8187- (void) folderSheetShow:       (id) sender;
    8288
    83 - (void) setPort:       (id) sender;
     89- (void) setPort:   (id) sender;
     90- (void) setNat:    (id) sender;
     91- (void) updateNatStatus;
     92
    8493- (void) setSpeedLimit: (id) sender;
    8594
  • trunk/macosx/PrefsController.m

    r850 r920  
    3434#define DOWNLOAD_ASK        3
    3535
    36 #define START_YES_CHECK_TAG     0
    37 #define START_WAIT_CHECK_TAG    1
    38 #define START_NO_CHECK_TAG      2
    39 
    4036#define UPDATE_DAILY    0
    4137#define UPDATE_WEEKLY   1
     
    8076- (void) dealloc
    8177{
     78    [fNatStatusTimer invalidate];
     79
    8280    [fDownloadFolder release];
    8381    [fImportFolder release];
     
    126124    [fPortField setIntValue: bindPort];
    127125    tr_setBindPort(fHandle, bindPort);
     126   
     127    //set NAT
     128    BOOL natShouldEnable = [fDefaults boolForKey: @"NatTraversal"];
     129    if (natShouldEnable)
     130        tr_natTraversalEnable(fHandle);
     131    [fNatCheck setState: natShouldEnable];
     132   
     133    fNatStatus = -1;
     134    [self updateNatStatus];
     135    fNatStatusTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self
     136                        selector: @selector(updateNatStatus) userInfo: nil repeats: YES];
    128137   
    129138    //checks for old version upload speed of -1
     
    250259        [fDefaults setObject: [fSeedingSoundPopUp titleOfSelectedItem] forKey: @"SeedingSound"];
    251260   
    252     //set start setting
    253     NSString * startSetting = [fDefaults stringForKey: @"StartSetting"];
    254     int tag;
    255     if ([startSetting isEqualToString: @"Start"])
    256         tag = START_YES_CHECK_TAG;
    257     else if ([startSetting isEqualToString: @"Wait"])
    258         tag = START_WAIT_CHECK_TAG;
    259     else
    260         tag = START_NO_CHECK_TAG;
    261    
    262     [fStartMatrix selectCellWithTag: tag];
    263     [fStartNumberField setEnabled: tag == START_WAIT_CHECK_TAG];
    264     [fStartNumberField setIntValue: [fDefaults integerForKey: @"WaitToStartNumber"]];
     261    //set start settings
     262    BOOL useQueue = [fDefaults boolForKey: @"Queue"];
     263    [fQueueCheck setState: useQueue];
     264    [fQueueNumberField setEnabled: useQueue];
     265    [fQueueNumberField setIntValue: [fDefaults integerForKey: @"QueueDownloadNumber"]];
     266   
     267    [fStartAtOpenCheck setState: [fDefaults boolForKey: @"StartAtOpen"]];
    265268   
    266269    //set private torrents
     
    355358        tr_setBindPort(fHandle, bindPort);
    356359        [fDefaults setInteger: bindPort forKey: @"BindPort"];
     360       
     361        [self updateNatStatus];
     362    }
     363}
     364
     365- (void) setNat: (id) sender
     366{
     367    BOOL enable = [sender state] == NSOnState;
     368    enable ? tr_natTraversalEnable(fHandle) : tr_natTraversalDisable(fHandle);
     369    [fDefaults setBool: enable forKey: @"NatTraversal"];
     370   
     371    [self updateNatStatus];
     372}
     373
     374- (void) updateNatStatus
     375{
     376    int status = tr_natTraversalStatus(fHandle);
     377    if (fNatStatus == status)
     378        return;
     379    fNatStatus = status;
     380   
     381    if (status == 2)
     382    {
     383        [fNatStatusField setStringValue: @"Ports successfully mapped"];
     384        [fNatStatusImage setImage: [NSImage imageNamed: @"Check.png"]];
     385    }
     386    else if (status == 3 || status == 4)
     387    {
     388        [fNatStatusField setStringValue: @"Error mapping ports"];
     389        [fNatStatusImage setImage: [NSImage imageNamed: @"Error.tiff"]];
     390    }
     391    else
     392    {
     393        [fNatStatusField setStringValue: @""];
     394        [fNatStatusImage setImage: nil];
    357395    }
    358396}
     
    662700}
    663701
    664 - (void) setStartSetting: (id) sender
    665 {
    666     NSString * startSetting;
    667 
    668     int tag = [[fStartMatrix selectedCell] tag];
    669     if (tag == START_YES_CHECK_TAG)
    670         startSetting = @"Start";
    671     else if (tag == START_WAIT_CHECK_TAG)
    672         startSetting = @"Wait";
    673     else
    674         startSetting = @"Manual";
    675    
    676     [fDefaults setObject: startSetting forKey: @"StartSetting"];
    677    
    678     [self setStartNumber: fStartNumberField];
    679     [fStartNumberField setEnabled: tag == START_WAIT_CHECK_TAG];
    680 }
    681 
    682 - (void) setStartNumber: (id) sender
    683 {
    684     int waitNumber = [sender intValue];
    685     if (![[sender stringValue] isEqualToString: [NSString stringWithInt: waitNumber]] || waitNumber < 1)
     702- (void) setStartAtOpen: (id) sender
     703{
     704    [fDefaults setBool: [sender state] == NSOnState forKey: @"StartAtOpen"];
     705}
     706
     707- (void) setUseQueue: (id) sender
     708{
     709    BOOL useQueue = [sender state] == NSOnState;
     710   
     711    [fDefaults setBool: useQueue forKey: @"Queue"];
     712    [self setQueueNumber: fQueueNumberField];
     713    [fQueueNumberField setEnabled: useQueue];
     714}
     715
     716- (void) setQueueNumber: (id) sender
     717{
     718    int queueNumber = [sender intValue];
     719    if (![[sender stringValue] isEqualToString: [NSString stringWithInt: queueNumber]] || queueNumber < 1)
    686720    {
    687721        NSBeep();
    688         waitNumber = [fDefaults floatForKey: @"WaitToStartNumber"];
    689         [sender setIntValue: waitNumber];
    690     }
    691     else
    692         [fDefaults setInteger: waitNumber forKey: @"WaitToStartNumber"];
     722        queueNumber = [fDefaults integerForKey: @"QueueDownloadNumber"];
     723        [sender setIntValue: queueNumber];
     724    }
     725    else
     726        [fDefaults setInteger: queueNumber forKey: @"QueueDownloadNumber"];
    693727   
    694728    [[NSNotificationCenter defaultCenter] postNotificationName: @"GlobalStartSettingChange" object: self];
  • trunk/macosx/Torrent.m

    r861 r920  
    5252                kBlue3 = BE(0x50A0FFFF), //80, 160, 255
    5353                kBlue4 = BE(0x1E46B4FF), //30, 70, 180
    54                 kGray  = BE(0x828282FF), //130, 130, 130
     54                kGray  = BE(0x969696FF), //150, 150, 150
    5555                kGreen = BE(0x00FF00FF), //0, 255, 0
    5656                kWhite = BE(0xFFFFFFFF); //255, 255, 255
     
    193193            if (fFinishedSeeding)
    194194                tempString = @"Seeding complete";
    195             else if (fWaitToStart && [[fDefaults stringForKey: @"StartSetting"] isEqualToString: @"Wait"])
     195            else if (fWaitToStart)
    196196                tempString = [@"Waiting to start" stringByAppendingEllipsis];
    197197            else
     
    316316}
    317317
     318- (void) startTransfer
     319{
     320    if (![self isActive])
     321    {
     322        tr_torrentStart(fHandle);
     323
     324        fFinishedSeeding = NO;
     325        fWaitToStart = NO;
     326    }
     327}
     328
     329- (void) stopTransfer
     330{
     331    if ([self isActive])
     332    {
     333        BOOL wasSeeding = [self isSeeding];
     334   
     335        tr_torrentStop(fHandle);
     336
     337        if (!wasSeeding)
     338            [[NSNotificationCenter defaultCenter] postNotificationName: @"StoppedDownloading" object: self];
     339    }
     340}
     341
     342- (void) stopTransferForQuit
     343{
     344    if ([self isActive])
     345        tr_torrentStop(fHandle);
     346}
     347
     348- (void) removeForever
     349{
     350    if (fPrivateTorrent)
     351        tr_torrentRemoveSaved(fHandle);
     352}
     353
     354- (void) sleep
     355{
     356    if ((fResumeOnWake = [self isActive]))
     357        tr_torrentStop(fHandle);
     358}
     359
     360- (void) wakeUp
     361{
     362    if (fResumeOnWake)
     363        tr_torrentStart(fHandle);
     364}
     365
     366- (float) ratio
     367{
     368    float downloaded = [self downloadedTotal];
     369    return downloaded > 0 ? (float)[self uploadedTotal] / downloaded : -1;
     370}
     371
     372- (int) stopRatioSetting
     373{
     374        return fStopRatioSetting;
     375}
     376
     377- (void) setStopRatioSetting: (int) setting
     378{
     379    fStopRatioSetting = setting;
     380}
     381
     382- (float) ratioLimit
     383{
     384    return fRatioLimit;
     385}
     386
     387- (void) setRatioLimit: (float) limit
     388{
     389    if (limit >= 0)
     390        fRatioLimit = limit;
     391}
     392
     393- (void) setWaitToStart: (BOOL) wait
     394{
     395    fWaitToStart = wait;
     396}
     397
     398- (BOOL) waitingToStart
     399{
     400    return fWaitToStart;
     401}
     402
     403- (void) revealData
     404{
     405    [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation] inFileViewerRootedAtPath: nil];
     406}
     407
     408- (void) trashData
     409{
     410    [self trashFile: [self dataLocation]];
     411}
     412
     413- (void) trashTorrent
     414{
     415    if (fPublicTorrent)
     416        [self trashFile: [self publicTorrentLocation]];
     417}
     418
     419- (NSImage *) icon
     420{
     421    return fIcon;
     422}
     423
     424- (NSImage *) iconFlipped
     425{
     426    return fIconFlipped;
     427}
     428
     429- (NSImage *) iconSmall
     430{
     431    return fIconSmall;
     432}
     433
     434- (NSString *) name
     435{
     436    return [NSString stringWithUTF8String: fInfo->name];
     437}
     438
     439- (uint64_t) size
     440{
     441    return fInfo->totalSize;
     442}
     443
     444- (NSString *) tracker
     445{
     446    return [NSString stringWithFormat: @"%s:%d", fInfo->trackerAddress, fInfo->trackerPort];
     447}
     448
     449- (NSString *) announce
     450{
     451    return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
     452}
     453
     454- (int) pieceSize
     455{
     456    return fInfo->pieceSize;
     457}
     458
     459- (int) pieceCount
     460{
     461    return fInfo->pieceCount;
     462}
     463
     464- (NSString *) hashString
     465{
     466    return [NSString stringWithUTF8String: fInfo->hashString];
     467}
     468
     469- (NSString *) torrentLocation
     470{
     471    return [NSString stringWithUTF8String: fInfo->torrent];
     472}
     473
     474- (NSString *) publicTorrentLocation
     475{
     476    return fPublicTorrentLocation;
     477}
     478
     479- (NSString *) torrentLocationString
     480{
     481    return fPrivateTorrent ? @"Transmission Support Folder" : [fPublicTorrentLocation stringByAbbreviatingWithTildeInPath];
     482}
     483
     484- (NSString *) dataLocation
     485{
     486    return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
     487}
     488
     489- (BOOL) publicTorrent
     490{
     491    return fPublicTorrent;
     492}
     493
     494- (BOOL) privateTorrent
     495{
     496    return fPrivateTorrent;
     497}
     498
     499- (NSString *) stateString
     500{
     501    switch( fStat->status )
     502    {
     503        case TR_STATUS_PAUSE:
     504            return @"Paused";
     505            break;
     506
     507        case TR_STATUS_CHECK:
     508            return [@"Checking existing files" stringByAppendingEllipsis];
     509            break;
     510
     511        case TR_STATUS_DOWNLOAD:
     512            return @"Downloading";
     513            break;
     514
     515        case TR_STATUS_SEED:
     516            return @"Seeding";
     517            break;
     518
     519        case TR_STATUS_STOPPING:
     520            return [@"Stopping" stringByAppendingEllipsis];
     521            break;
     522       
     523        default:
     524            return @"N/A";
     525    }
     526}
     527
     528- (float) progress
     529{
     530    return fStat->progress;
     531}
     532
     533- (int) eta
     534{
     535    return fStat->eta;
     536}
     537
     538- (BOOL) isActive
     539{
     540    return fStat->status & TR_STATUS_ACTIVE;
     541}
     542
     543- (BOOL) isSeeding
     544{
     545    return fStat->status == TR_STATUS_SEED;
     546}
     547
     548- (BOOL) isPaused
     549{
     550    return fStat->status == TR_STATUS_PAUSE;
     551}
     552
     553- (BOOL) isError
     554{
     555    return fStat->error & TR_ETRACKER;
     556}
     557
     558- (BOOL) justFinished
     559{
     560    return tr_getFinished(fHandle);
     561}
     562
     563- (NSArray *) peers
     564{
     565    int totalPeers, i;
     566    tr_peer_stat_t * peers = tr_torrentPeers(fHandle, & totalPeers);
     567   
     568    NSMutableArray * peerDics = [NSMutableArray arrayWithCapacity: totalPeers];
     569    tr_peer_stat_t peer;
     570    NSString * client;
     571    for (i = 0; i < totalPeers; i++)
     572    {
     573        peer = peers[i];
     574        [peerDics addObject: [NSDictionary dictionaryWithObjectsAndKeys:
     575            [NSNumber numberWithBool: peer.isConnected], @"Connected",
     576            [NSString stringWithCString: (char *) peer.addr encoding: NSUTF8StringEncoding], @"IP",
     577            [NSString stringWithCString: (char *) peer.client encoding: NSUTF8StringEncoding], @"Client",
     578            [NSNumber numberWithBool: peer.isDownloading], @"UL To",
     579            [NSNumber numberWithBool: peer.isUploading], @"DL From", nil]];
     580    }
     581   
     582    tr_torrentPeersFree(peers, totalPeers);
     583   
     584    return peerDics;
     585}
     586
     587- (NSString *) progressString
     588{
     589    return fProgressString;
     590}
     591
     592- (NSString *) statusString
     593{
     594    return fStatusString;
     595}
     596
     597- (NSString *) shortStatusString
     598{
     599    return fShortStatusString;
     600}
     601
     602- (NSString *) remainingTimeString
     603{
     604    return fRemainingTimeString;
     605}
     606
     607- (int) seeders
     608{
     609    return fStat->seeders;
     610}
     611
     612- (int) leechers
     613{
     614    return fStat->leechers;
     615}
     616
     617- (int) totalPeers
     618{
     619    return fStat->peersTotal;
     620}
     621
     622//peers uploading to you
     623- (int) peersUploading
     624{
     625    return fStat->peersUploading;
     626}
     627
     628//peers downloading from you
     629- (int) peersDownloading
     630{
     631    return fStat->peersDownloading;
     632}
     633
     634- (float) downloadRate
     635{
     636    return fStat->rateDownload;
     637}
     638
     639- (float) uploadRate
     640{
     641    return fStat->rateUpload;
     642}
     643
     644- (float) downloadedValid
     645{
     646    return [self progress] * [self size];
     647}
     648
     649- (uint64_t) downloadedTotal
     650{
     651    return fStat->downloaded;
     652}
     653
     654- (uint64_t) uploadedTotal
     655{
     656    return fStat->uploaded;
     657}
     658
     659- (float) swarmSpeed
     660{
     661    return fStat->swarmspeed;
     662}
     663
     664- (NSNumber *) orderValue
     665{
     666    return [NSNumber numberWithInt: fOrderValue];
     667}
     668
     669- (void) setOrderValue: (int) orderValue
     670{
     671    fOrderValue = orderValue;
     672}
     673
     674- (NSArray *) fileList
     675{
     676    int count = fInfo->fileCount, i;
     677    tr_file_t file;
     678    NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
     679   
     680    for (i = 0; i < count; i++)
     681    {
     682        file = fInfo->files[i];
     683        [files addObject: [NSDictionary dictionaryWithObjectsAndKeys:
     684            [[self downloadFolder] stringByAppendingPathComponent: [NSString stringWithUTF8String: file.name]], @"Name",
     685            [NSNumber numberWithUnsignedLongLong: file.length], @"Size", nil]];
     686    }
     687   
     688    return files;
     689}
     690
     691- (NSDate *) date
     692{
     693    return fDate;
     694}
     695
     696- (NSNumber *) stateSortKey
     697{
     698    if (![self isActive])
     699        return [NSNumber numberWithInt: 0];
     700    else if ([self isSeeding])
     701        return [NSNumber numberWithInt: 1];
     702    else
     703        return [NSNumber numberWithInt: 2];
     704}
     705
     706- (NSNumber *) progressSortKey
     707{
     708    //if finished downloading sort by ratio instead of progress
     709    float progress = [self progress];
     710    return [NSNumber numberWithFloat: progress < 1.0 ? progress : 2.0 + [self ratio]];
     711}
     712
     713@end
     714
     715
     716@implementation Torrent (Private)
     717
     718//if a hash is given, attempt to load that; otherwise, attempt to open file at path
     719- (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
     720        privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
     721        date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
     722        ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
     723        orderValue: (NSNumber *) orderValue
     724{
     725    if (!(self = [super init]))
     726        return nil;
     727
     728    fLib = lib;
     729    fDefaults = [NSUserDefaults standardUserDefaults];
     730
     731    fPrivateTorrent = privateTorrent ? [privateTorrent boolValue] : [fDefaults boolForKey: @"SavePrivateTorrent"];
     732    fPublicTorrent = !fPrivateTorrent || (publicTorrent ? [publicTorrent boolValue]
     733                                            : ![fDefaults boolForKey: @"DeleteOriginalTorrent"]);
     734
     735    int error;
     736    if (fPrivateTorrent && hashString)
     737        fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error);
     738   
     739    if (!fHandle && path)
     740        fHandle = tr_torrentInit(fLib, [path UTF8String], fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error);
     741
     742    if (!fHandle)
     743    {
     744        [self release];
     745        return nil;
     746    }
     747   
     748    fInfo = tr_torrentInfo( fHandle );
     749
     750    if (fPublicTorrent)
     751        fPublicTorrentLocation = [path retain];
     752
     753    fDate = date ? [date retain] : [[NSDate alloc] init];
     754   
     755    fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
     756    fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
     757    fFinishedSeeding = NO;
     758   
     759    fWaitToStart = waitToStart ? [waitToStart boolValue] : [fDefaults boolForKey: @"StartAtOpen"];
     760    fOrderValue = orderValue ? [orderValue intValue] : tr_torrentCount(fLib) - 1;
     761   
     762    NSString * fileType = fInfo->multifile ? NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
     763    fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
     764    [fIcon retain];
     765   
     766    fIconFlipped = [fIcon copy];
     767    [fIconFlipped setFlipped: YES];
     768   
     769    fIconSmall = [fIconFlipped copy];
     770    [fIconSmall setScalesWhenResized: YES];
     771    [fIconSmall setSize: NSMakeSize(16.0, 16.0)];
     772
     773    fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
     774    fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
     775    fShortStatusString = [[NSMutableString alloc] initWithCapacity: 30];
     776    fRemainingTimeString = [[NSMutableString alloc] initWithCapacity: 30];
     777
     778    [self update];
     779    return self;
     780}
     781
    318782- (NSImage *) advancedBar
    319783{
    320     #warning figure out length
    321784    int width = 250; //integers for bars
    322785   
     
    351814        p[w + bytesPerRow / 4] = kGreen;
    352815    }
    353     for (; w < width - 2; w++)
     816    for (; w < width; w++)
    354817    {
    355818        p[w] = kWhite;
     
    362825    {
    363826        if (pieces[w] < 0)
     827            color = kGreen;
     828        else if (pieces[w] == 0)
    364829            color = kGray;
    365         else if (pieces[w] == 0)
    366             color = kRed;
    367830        else if (pieces[w] == 1)
    368831            color = kBlue1;
     
    393856}
    394857
    395 - (void) startTransfer
    396 {
    397     if (![self isActive])
    398     {
    399         tr_torrentStart(fHandle);
    400 
    401         fFinishedSeeding = NO;
    402         fWaitToStart = NO;
    403        
    404         [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentSettingChange" object: self];
    405     }
    406 }
    407 
    408 - (void) stopTransfer
    409 {
    410     if ([self isActive])
    411     {
    412         BOOL wasSeeding = [self isSeeding];
    413    
    414         tr_torrentStop(fHandle);
    415 
    416         if (!wasSeeding)
    417             [[NSNotificationCenter defaultCenter] postNotificationName: @"StoppedDownloading" object: self];
    418     }
    419 }
    420 
    421 - (void) stopTransferForQuit
    422 {
    423     if ([self isActive])
    424         tr_torrentStop(fHandle);
    425 }
    426 
    427 - (void) removeForever
    428 {
    429     if (fPrivateTorrent)
    430         tr_torrentRemoveSaved(fHandle);
    431 }
    432 
    433 - (void) sleep
    434 {
    435     if ((fResumeOnWake = [self isActive]))
    436         tr_torrentStop(fHandle);
    437 }
    438 
    439 - (void) wakeUp
    440 {
    441     if (fResumeOnWake)
    442         tr_torrentStart(fHandle);
    443 }
    444 
    445 - (float) ratio
    446 {
    447     float downloaded = [self downloadedTotal];
    448     return downloaded > 0 ? (float)[self uploadedTotal] / downloaded : -1;
    449 }
    450 
    451 - (int) stopRatioSetting
    452 {
    453         return fStopRatioSetting;
    454 }
    455 
    456 - (void) setStopRatioSetting: (int) setting
    457 {
    458     fStopRatioSetting = setting;
    459 }
    460 
    461 - (float) ratioLimit
    462 {
    463     return fRatioLimit;
    464 }
    465 
    466 - (void) setRatioLimit: (float) limit
    467 {
    468     if (limit >= 0)
    469         fRatioLimit = limit;
    470 }
    471 
    472 - (void) setWaitToStart: (BOOL) wait
    473 {
    474     fWaitToStart = wait;
    475 }
    476 
    477 - (BOOL) waitingToStart
    478 {
    479     return fWaitToStart;
    480 }
    481 
    482 - (void) revealData
    483 {
    484     [[NSWorkspace sharedWorkspace] selectFile: [self dataLocation] inFileViewerRootedAtPath: nil];
    485 }
    486 
    487 - (void) trashData
    488 {
    489     [self trashFile: [self dataLocation]];
    490 }
    491 
    492 - (void) trashTorrent
    493 {
    494     if (fPublicTorrent)
    495         [self trashFile: [self publicTorrentLocation]];
    496 }
    497 
    498 - (NSImage *) icon
    499 {
    500     return fIcon;
    501 }
    502 
    503 - (NSImage *) iconFlipped
    504 {
    505     return fIconFlipped;
    506 }
    507 
    508 - (NSImage *) iconSmall
    509 {
    510     return fIconSmall;
    511 }
    512 
    513 - (NSString *) name
    514 {
    515     return [NSString stringWithUTF8String: fInfo->name];
    516 }
    517 
    518 - (uint64_t) size
    519 {
    520     return fInfo->totalSize;
    521 }
    522 
    523 - (NSString *) tracker
    524 {
    525     return [NSString stringWithFormat: @"%s:%d", fInfo->trackerAddress, fInfo->trackerPort];
    526 }
    527 
    528 - (NSString *) announce
    529 {
    530     return [NSString stringWithUTF8String: fInfo->trackerAnnounce];
    531 }
    532 
    533 - (int) pieceSize
    534 {
    535     return fInfo->pieceSize;
    536 }
    537 
    538 - (int) pieceCount
    539 {
    540     return fInfo->pieceCount;
    541 }
    542 
    543 - (NSString *) hashString
    544 {
    545     return [NSString stringWithUTF8String: fInfo->hashString];
    546 }
    547 
    548 - (NSString *) torrentLocation
    549 {
    550     return [NSString stringWithUTF8String: fInfo->torrent];
    551 }
    552 
    553 - (NSString *) publicTorrentLocation
    554 {
    555     return fPublicTorrentLocation;
    556 }
    557 
    558 - (NSString *) torrentLocationString
    559 {
    560     return fPrivateTorrent ? @"Transmission Support Folder" : [fPublicTorrentLocation stringByAbbreviatingWithTildeInPath];
    561 }
    562 
    563 - (NSString *) dataLocation
    564 {
    565     return [[self downloadFolder] stringByAppendingPathComponent: [self name]];
    566 }
    567 
    568 - (BOOL) publicTorrent
    569 {
    570     return fPublicTorrent;
    571 }
    572 
    573 - (BOOL) privateTorrent
    574 {
    575     return fPrivateTorrent;
    576 }
    577 
    578 - (NSString *) stateString
    579 {
    580     switch( fStat->status )
    581     {
    582         case TR_STATUS_PAUSE:
    583             return @"Paused";
    584             break;
    585 
    586         case TR_STATUS_CHECK:
    587             return [@"Checking existing files" stringByAppendingEllipsis];
    588             break;
    589 
    590         case TR_STATUS_DOWNLOAD:
    591             return @"Downloading";
    592             break;
    593 
    594         case TR_STATUS_SEED:
    595             return @"Seeding";
    596             break;
    597 
    598         case TR_STATUS_STOPPING:
    599             return [@"Stopping" stringByAppendingEllipsis];
    600             break;
    601        
    602         default:
    603             return @"N/A";
    604     }
    605 }
    606 
    607 - (float) progress
    608 {
    609     return fStat->progress;
    610 }
    611 
    612 - (int) eta
    613 {
    614     return fStat->eta;
    615 }
    616 
    617 - (BOOL) isActive
    618 {
    619     return fStat->status & TR_STATUS_ACTIVE;
    620 }
    621 
    622 - (BOOL) isSeeding
    623 {
    624     return fStat->status == TR_STATUS_SEED;
    625 }
    626 
    627 - (BOOL) isPaused
    628 {
    629     return fStat->status == TR_STATUS_PAUSE;
    630 }
    631 
    632 - (BOOL) isError
    633 {
    634     return fStat->error & TR_ETRACKER;
    635 }
    636 
    637 - (BOOL) justFinished
    638 {
    639     return tr_getFinished(fHandle);
    640 }
    641 
    642 - (NSArray *) peers
    643 {
    644     int totalPeers, i;
    645     tr_peer_stat_t * peers = tr_torrentPeers(fHandle, & totalPeers);
    646    
    647     NSMutableArray * peerDics = [NSMutableArray arrayWithCapacity: totalPeers];
    648     tr_peer_stat_t peer;
    649     NSString * client;
    650     for (i = 0; i < totalPeers; i++)
    651     {
    652         peer = peers[i];
    653         [peerDics addObject: [NSDictionary dictionaryWithObjectsAndKeys:
    654             [NSNumber numberWithBool: peer.isConnected], @"Connected",
    655             [NSString stringWithCString: (char *) peer.addr encoding: NSUTF8StringEncoding], @"IP",
    656             [NSString stringWithCString: (char *) peer.client encoding: NSUTF8StringEncoding], @"Client",
    657             [NSNumber numberWithBool: peer.isDownloading], @"UL To",
    658             [NSNumber numberWithBool: peer.isUploading], @"DL From", nil]];
    659     }
    660    
    661     tr_torrentPeersFree(peers, totalPeers);
    662    
    663     return peerDics;
    664 }
    665 
    666 - (NSString *) progressString
    667 {
    668     return fProgressString;
    669 }
    670 
    671 - (NSString *) statusString
    672 {
    673     return fStatusString;
    674 }
    675 
    676 - (NSString *) shortStatusString
    677 {
    678     return fShortStatusString;
    679 }
    680 
    681 - (NSString *) remainingTimeString
    682 {
    683     return fRemainingTimeString;
    684 }
    685 
    686 - (int) seeders
    687 {
    688     return fStat->seeders;
    689 }
    690 
    691 - (int) leechers
    692 {
    693     return fStat->leechers;
    694 }
    695 
    696 - (int) totalPeers
    697 {
    698     return fStat->peersTotal;
    699 }
    700 
    701 //peers uploading to you
    702 - (int) peersUploading
    703 {
    704     return fStat->peersUploading;
    705 }
    706 
    707 //peers downloading from you
    708 - (int) peersDownloading
    709 {
    710     return fStat->peersDownloading;
    711 }
    712 
    713 - (float) downloadRate
    714 {
    715     return fStat->rateDownload;
    716 }
    717 
    718 - (float) uploadRate
    719 {
    720     return fStat->rateUpload;
    721 }
    722 
    723 - (float) downloadedValid
    724 {
    725     return [self progress] * [self size];
    726 }
    727 
    728 - (uint64_t) downloadedTotal
    729 {
    730     return fStat->downloaded;
    731 }
    732 
    733 - (uint64_t) uploadedTotal
    734 {
    735     return fStat->uploaded;
    736 }
    737 
    738 - (float) swarmSpeed
    739 {
    740     return fStat->swarmspeed;
    741 }
    742 
    743 - (NSNumber *) orderValue
    744 {
    745     return [NSNumber numberWithInt: fOrderValue];
    746 }
    747 
    748 - (void) setOrderValue: (int) orderValue
    749 {
    750     fOrderValue = orderValue;
    751 }
    752 
    753 - (NSArray *) fileList
    754 {
    755     int count = fInfo->fileCount, i;
    756     tr_file_t file;
    757     NSMutableArray * files = [NSMutableArray arrayWithCapacity: count];
    758    
    759     for (i = 0; i < count; i++)
    760     {
    761         file = fInfo->files[i];
    762         [files addObject: [NSDictionary dictionaryWithObjectsAndKeys:
    763             [[self downloadFolder] stringByAppendingPathComponent: [NSString stringWithUTF8String: file.name]], @"Name",
    764             [NSNumber numberWithUnsignedLongLong: file.length], @"Size", nil]];
    765     }
    766    
    767     return files;
    768 }
    769 
    770 - (NSDate *) date
    771 {
    772     return fDate;
    773 }
    774 
    775 - (NSNumber *) stateSortKey
    776 {
    777     if (![self isActive])
    778         return [NSNumber numberWithInt: 0];
    779     else if ([self isSeeding])
    780         return [NSNumber numberWithInt: 1];
    781     else
    782         return [NSNumber numberWithInt: 2];
    783 }
    784 
    785 - (NSNumber *) progressSortKey
    786 {
    787     //if finished downloading sort by ratio instead of progress
    788     float progress = [self progress];
    789     return [NSNumber numberWithFloat: progress < 1.0 ? progress : 2.0 + [self ratio]];
    790 }
    791 
    792 @end
    793 
    794 
    795 @implementation Torrent (Private)
    796 
    797 //if a hash is given, attempt to load that; otherwise, attempt to open file at path
    798 - (id) initWithHash: (NSString *) hashString path: (NSString *) path lib: (tr_handle_t *) lib
    799         privateTorrent: (NSNumber *) privateTorrent publicTorrent: (NSNumber *) publicTorrent
    800         date: (NSDate *) date stopRatioSetting: (NSNumber *) stopRatioSetting
    801         ratioLimit: (NSNumber *) ratioLimit waitToStart: (NSNumber *) waitToStart
    802         orderValue: (NSNumber *) orderValue
    803 {
    804     if (!(self = [super init]))
    805         return nil;
    806 
    807     fLib = lib;
    808     fDefaults = [NSUserDefaults standardUserDefaults];
    809 
    810     fPrivateTorrent = privateTorrent ? [privateTorrent boolValue] : [fDefaults boolForKey: @"SavePrivateTorrent"];
    811     fPublicTorrent = !fPrivateTorrent || (publicTorrent ? [publicTorrent boolValue]
    812                                             : ![fDefaults boolForKey: @"DeleteOriginalTorrent"]);
    813 
    814     int error;
    815     if (fPrivateTorrent && hashString)
    816         fHandle = tr_torrentInitSaved(fLib, [hashString UTF8String], TR_FSAVEPRIVATE, & error);
    817    
    818     if (!fHandle && path)
    819         fHandle = tr_torrentInit(fLib, [path UTF8String], fPrivateTorrent ? TR_FSAVEPRIVATE : 0, & error);
    820 
    821     if (!fHandle)
    822     {
    823         [self release];
    824         return nil;
    825     }
    826    
    827     fInfo = tr_torrentInfo( fHandle );
    828 
    829     if (fPublicTorrent)
    830         fPublicTorrentLocation = [path retain];
    831 
    832     fDate = date ? [date retain] : [[NSDate alloc] init];
    833    
    834     fStopRatioSetting = stopRatioSetting ? [stopRatioSetting intValue] : -1;
    835     fRatioLimit = ratioLimit ? [ratioLimit floatValue] : [fDefaults floatForKey: @"RatioLimit"];
    836     fFinishedSeeding = NO;
    837    
    838     fWaitToStart = waitToStart ? [waitToStart boolValue]
    839                     : ![[fDefaults stringForKey: @"StartSetting"] isEqualToString: @"Manual"];
    840     fOrderValue = orderValue ? [orderValue intValue] : tr_torrentCount(fLib) - 1;
    841    
    842     NSString * fileType = fInfo->multifile ? NSFileTypeForHFSTypeCode('fldr') : [[self name] pathExtension];
    843     fIcon = [[NSWorkspace sharedWorkspace] iconForFileType: fileType];
    844     [fIcon retain];
    845    
    846     fIconFlipped = [fIcon copy];
    847     [fIconFlipped setFlipped: YES];
    848    
    849     fIconSmall = [fIconFlipped copy];
    850     [fIconSmall setScalesWhenResized: YES];
    851     [fIconSmall setSize: NSMakeSize(16.0, 16.0)];
    852 
    853     fProgressString = [[NSMutableString alloc] initWithCapacity: 50];
    854     fStatusString = [[NSMutableString alloc] initWithCapacity: 75];
    855     fShortStatusString = [[NSMutableString alloc] initWithCapacity: 30];
    856     fRemainingTimeString = [[NSMutableString alloc] initWithCapacity: 30];
    857 
    858     [self update];
    859     return self;
    860 }
    861 
    862858- (void) trashFile: (NSString *) path
    863859{
  • trunk/macosx/TorrentCell.m

    r858 r920  
    152152    NSDictionary * info = [self objectValue];
    153153   
    154     //if seeding, there's no need for the advanced bar
    155     if ([[info objectForKey: @"Seeding"] boolValue])
    156     {
    157         [self buildSimpleBar: widthFloat point: point];
    158         return;
    159     }
    160    
    161154    //draw overlay over advanced bar
    162155    [fProgressEndAdvanced compositeToPoint: point operation: NSCompositeSourceOver];
  • trunk/macosx/TorrentTableView.h

    r699 r920  
    4040   
    4141    IBOutlet NSMenu     * fContextRow, * fContextNoRow;
    42     NSImage             * fResumeOnIcon, * fResumeOffIcon, * fPauseOnIcon, * fPauseOffIcon,
     42    NSImage             * fResumeOnIcon, * fResumeOffIcon,
     43                        * fPauseOnIcon, * fPauseOffIcon,
     44                        * fResumeNoWaitOnIcon, * fResumeNoWaitOffIcon,
    4345                        * fRevealOnIcon, * fRevealOffIcon;
    4446   
  • trunk/macosx/TorrentTableView.m

    r729 r920  
    5656        fResumeOffIcon = [NSImage imageNamed: @"ResumeOff.png"];
    5757        fPauseOnIcon = [NSImage imageNamed: @"PauseOn.png"];
     58        fResumeNoWaitOnIcon = [NSImage imageNamed: @"ResumeNoWaitOn.png"];
     59        fResumeNoWaitOffIcon = [NSImage imageNamed: @"ResumeNoWaitOff.png"];
    5860        fPauseOffIcon = [NSImage imageNamed: @"PauseOff.png"];
    5961        fRevealOnIcon = [NSImage imageNamed: @"RevealOn.png"];
     
    9597    fClickPoint = [self convertPoint: [event locationInWindow] fromView: nil];
    9698
    97     if ([event modifierFlags] & NSAlternateKeyMask)
    98     {
    99         [fController toggleAdvancedBar: self];
    100         fClickPoint = NSZeroPoint;
    101     }
    102     else if (![self pointInPauseRect: fClickPoint] && ![self pointInRevealRect: fClickPoint])
    103     {
    104         if ([self pointInMinimalStatusRect: fClickPoint])
    105             [(TorrentCell *)[[self tableColumnWithIdentifier: @"Torrent"] dataCell] toggleMinimalStatus];
    106 
    107         [super mouseDown: event];
     99    if (![self pointInPauseRect: fClickPoint] && ![self pointInRevealRect: fClickPoint])
     100    {
     101        if ([event modifierFlags] & NSAlternateKeyMask)
     102        {
     103            [fController toggleAdvancedBar: self];
     104            fClickPoint = NSZeroPoint;
     105        }
     106        else
     107        {
     108            if ([self pointInMinimalStatusRect: fClickPoint])
     109                [(TorrentCell *)[[self tableColumnWithIdentifier: @"Torrent"] dataCell] toggleMinimalStatus];
     110
     111            [super mouseDown: event];
     112        }
    108113    }
    109114    else;
     
    122127        Torrent * torrent = [fTorrents objectAtIndex: row];
    123128
    124                 if ([torrent isPaused])
    125                         [fController resumeTorrents: [NSArray arrayWithObject: torrent]];
    126                 else if ([torrent isActive])
     129        if ([torrent isActive])
    127130            [fController stopTorrents: [NSArray arrayWithObject: torrent]];
    128                 else;
     131        else if ([torrent isPaused])
     132        {
     133            if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
     134                [fController resumeTorrentsNoWait: [NSArray arrayWithObject: torrent]];
     135            else if ([torrent waitingToStart])
     136                [fController stopTorrents: [NSArray arrayWithObject: torrent]];
     137            else
     138                [fController resumeTorrents: [NSArray arrayWithObject: torrent]];
     139        }
     140        else;
    129141    }
    130142    else if (sameRow && [self pointInRevealRect: point] && [self pointInRevealRect: fClickPoint])
    131143        [[fTorrents objectAtIndex: row] revealData];
    132         else if ([event clickCount] == 2)
     144    else if ([event clickCount] == 2)
    133145    {
    134146        if ([self pointInIconRect: point])
     
    139151    else;
    140152   
    141         [super mouseUp: event];
     153    [super mouseUp: event];
    142154
    143155    fClickPoint = NSZeroPoint;
     
    183195        [super keyDown: event];
    184196    }
     197}
     198
     199- (void) flagsChanged: (NSEvent *) event
     200{
     201    [self display];
     202    [super flagsChanged: event];
    185203}
    186204
     
    224242        rect  = [self pauseRectForRow: i];
    225243
    226         if ([torrent isPaused])
    227             image = NSPointInRect(fClickPoint, rect) ? fResumeOnIcon : fResumeOffIcon;
    228         else if ([torrent isActive])
     244        if ([torrent isActive])
    229245            image = NSPointInRect(fClickPoint, rect) ? fPauseOnIcon : fPauseOffIcon;
     246        else if ([torrent isPaused])
     247        {
     248            if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask && [fDefaults boolForKey: @"Queue"])
     249                image = NSPointInRect(fClickPoint, rect) ? fResumeNoWaitOnIcon : fResumeNoWaitOffIcon;
     250            else if ([torrent waitingToStart])
     251                image = NSPointInRect(fClickPoint, rect) ? fPauseOnIcon : fPauseOffIcon;
     252            else
     253                image = NSPointInRect(fClickPoint, rect) ? fResumeOnIcon : fResumeOffIcon;
     254        }
    230255        else
    231256            image = nil;
  • trunk/mk/common.mk

    r912 r920  
    11# $Id$
    22
    3 TMPCFLAGS   = -g -Wall -W -O3 -funroll-loops -D_FILE_OFFSET_BITS=64 \
     3TMPCFLAGS   = -g -Wall -W -D_FILE_OFFSET_BITS=64 \
    44              -D_LARGEFILE_SOURCE -D_GNU_SOURCE \
    55              -DSYS_$(shell echo $(SYSTEM) | tr a-z A-Z)
  • trunk/mk/lib.mk

    r265 r920  
    66SRCS = transmission.c bencode.c net.c tracker.c peer.c inout.c \
    77       metainfo.c sha1.c utils.c fdlimit.c clients.c completion.c \
    8        platform.c ratecontrol.c choking.c
     8       platform.c ratecontrol.c choking.c natpmp.c upnp.c http.c xml.c
    99OBJS = $(SRCS:%.c=%.o)
    1010
Note: See TracChangeset for help on using the changeset viewer.