public static void sendFile
	(
		Socket sckIn
		, String strId
		, EzimFileOut efoIn
	)
		throws Exception
	{
		if (efoIn != null)
		{
			efoIn.setSocket(sckIn);

			EzimDtxSemantics.initByteArrays();

			byte[] bTmp = new byte[EzimNetwork.dtxBufLen];
			int iTmp = 0;
			long lCnt = 0;
			long lCLen = 0;

			FileInputStream fisTmp = null;

			try
			{
				OutputStream osTmp = sckIn.getOutputStream();
				lCLen = efoIn.getFile().length();
				fisTmp = new FileInputStream(efoIn.getFile());

				// create necessary header fields
				Hashtable<String, String> htTmp
					= new Hashtable<String, String>();

				htTmp.put
				(
					EzimDtxSemantics.HDR_CTYPE
					, EzimDtxFileSemantics.CTYPE_FILE
				);
				htTmp.put
				(
					EzimDtxSemantics.HDR_CLEN
					, Long.toString(lCLen)
				);
				htTmp.put
				(
					EzimDtxFileSemantics.HDR_FILEREQID
					, strId
				);

				// output header in bytes
				EzimDtxSemantics.sendHeaderBytes(sckIn, htTmp);

				efoIn.setSize(lCLen);
				efoIn.setProgressed(lCnt);
				// convert and output file contents in bytes
				while(! ((iTmp = fisTmp.read(bTmp)) < 0))
				{
					osTmp.write(bTmp, 0, iTmp);
					lCnt += iTmp;
					efoIn.setProgressed(lCnt);
				}

				// make sure everything is sent
				osTmp.flush();
			}
			catch(SocketException se)
			{
				// connection closed by remote
			}
			finally
			{
				try
				{
					if (fisTmp != null) fisTmp.close();
				}
				catch(Exception e)
				{
					EzimLogger.getInstance().severe(e.getMessage(), e);
				}

				String strSysMsg = null;

				if (lCnt < lCLen)
					strSysMsg = EzimLang.TransmissionAbortedByRemote;
				else if (lCnt == lCLen)
					strSysMsg = EzimLang.Done;

				efoIn.endProgress(strSysMsg);
			}
		}
	}